API для организаций: выгрузка намерений
Организации загружают в «ХочуМогу» каталог товаров пакетно — по ссылке на файл или прямым вызовом API, без ручного ввода через мастер. Конвейер сам превращает позиции каталога в намерения «Могу продать». Оба способа уже работают и доступны в личном кабинете организации, пилюля «Каталог»: блок «Импорт по ссылке» (поле URL, автосинхронизация, кнопка «Проверить сейчас») и «Подключение по API» (выпуск токена доступа).
У импорта два режима. Разделы 1–7 ниже описывают обычный каталог (legacy): у намерения одна цена, количество и территория. Для разных остатков и цен в магазинах или на складах настройте источник наличия по точкам (locations), как описано в конце страницы. У него отдельные снимки наличия и планы получения; правила обычного каталога о «Договорной», «Неограничено», городе профиля и закрытии пропавших к нему не применяйте.
1. Аутентификация
Прямой вызов авторизуется персональным токеном организации в заголовке Authorization: Bearer <org_token>. Токен выдаётся в личном кабинете организации (пилюля «Каталог» → «Подключение по API» → «Выпустить ключ»), показывается один раз в момент выпуска и привязан к аккаунту — загруженные товары становятся намерениями от его имени. Для импорта «по ссылке» токен не нужен: фидом управляет сама организация под обычной сессией в личном кабинете.
2. Два способа загрузки
Оба принимают один и тот же формат файла (раздел 3 ниже).
- Прямой вызов (push). Один запрос — один прогон синхронизации:
POST /v1/org/intentions/importс телом-файлом. - По ссылке (pull). Организация указывает один или несколько URL файлов в блоке «Импорт по ссылке» личного кабинета; сервис сам периодически забирает каждую ссылку и синхронизирует её отдельно (подробности — раздел 6).
POST /v1/org/intentions/import?dry_run=1
Authorization: Bearer nmr_org_<32 hex-символа>
Content-Type: application/xml
# тело — сам XML-файл целиком, БЕЗ JSON-обёртки (см. формат ниже)
В счётчиках отчёта есть no_photo — сколько товаров пришло без единой картинки. Такой товар публикуется как обычно, просто без фотографии: положить её можем только вы, добавив <picture> в выгрузку. Товары, у которых ссылка на картинку есть, но не открывается, в это число не входят.
Там же desc_truncated — у скольких товаров описание пришлось сократить: описание намерения вмещает 6000 символов вместе с названием товара. Товар при этом публикуется, сокращение идёт по границе абзаца или строки.
Рядом со счётчиками ответ несёт поле report (с 22.09.2026) — тот же прогон, свёрнутый до читаемого отчёта: сколько позиций было в файле, сколько отсеяно по available="false", как распределились фотографии, цены и количества, и какие причины отказов встретились чаще всего. Разбор — в разделе 5.
dry_run=1 — сухой прогон: тот же отчёт, что и боевой импорт, но без создания и изменения намерений (пригодится, чтобы проверить файл перед первой загрузкой). remove_missing=1 — закрыть намерения, чьи товары пропали из текущего файла (без параметра пропавшие товары остаются как есть).
3. Формат файла: YML Яндекс.Маркета
Сервис принимает один формат — YML Яндекс.Маркета (XML), тот самый файл, который у вас, скорее всего, уже есть: его выгружают 1С-Битрикс, InSales и другие системы, обычно по адресу вида /bitrix/catalog_export/yandex_НОМЕР.php. Ничего специально готовить не нужно — дайте ссылку на существующую выгрузку либо проверьте файл сухим прогоном перед загрузкой. Формат определяется по содержимому файла, расширение ссылки и заголовок Content-Type значения не имеют; файл в любом другом формате сервис не примет (раздел 5, код 422).
Что сервис берёт из YML: название товара, описание <description>, цену, категорию (путь по дереву <categories> собирается автоматически по <categoryId>), производителя <vendor>, артикул <vendorCode>, характеристики <param> и изображения <picture> — картинки скачиваются к нам и показываются на карточке намерения (ссылки на ваш сайт мы не сохраняем: они перестанут работать, если вы переставите файлы). Берётся несколько первых картинок товара — сколько именно, настраивает оператор сервиса, по умолчанию три. Перенос идёт фоном после импорта, поэтому фотографии появляются на несколько минут позже самих намерений. Если какие-то картинки не доехали (ваш сервер был недоступен, ссылка временно не работала), сервис доберёт их при следующем прогоне фида — заново загружать выгрузку не нужно. Одна и та же картинка, поставленная у нескольких товаров, хранится у нас один раз и достаётся всем им. Товары с available="false" пропускаются — намерение «могу продать» о том, чего нет на складе, никому не поможет; сколько их было, видно в отчёте счётчиком unavailable (раздел 5) — это самый частый ответ на вопрос «куда делись мои товары». Кодировка windows-1251, в которой Битрикс выгружает по умолчанию, распознаётся сама.
Файл — список товаров вашего каталога, а не готовых намерений: сервис сам решает, во что превратить каждый товар. Как поле обязателен только атрибут id у <offer> — без него запись не свяжется с намерением, сервис вернёт по товару ошибку и не создаст черновик. <categoryId> тоже нужен практически всегда: без категории товар не пропадает с ошибкой всего запроса, но пропускается (раздел 5). Дальше — не поля, а требования к результату: импорт всегда создаёт намерения «Могу продать», а для этого типа нужен хотя бы один тег, который узнает словарь характеристик. Цена и количество обязательными не являются: если их в файле нет, намерение публикуется со стоимостью «Договорная» и количеством «Неограничено». Всё это разобрано в подсказках под примером.
<?xml version="1.0" encoding="utf-8"?>
<yml_catalog>
<shop>
<name>Мой магазин</name>
<categories>
<category id="40">Инструменты</category>
<category id="50" parentId="40">Электроинструмент</category>
<category id="60" parentId="50">Дрели-шуруповёрты</category>
<category id="10">Женщинам</category>
<category id="20" parentId="10">Женская одежда</category>
<category id="30" parentId="20">Платья</category>
</categories>
<offers>
<offer id="sku-101">
<name>Дрель-шуруповёрт Bosch GSR 12V-15, 2 АКБ, кейс</name>
<description><![CDATA[<p>Компактная дрель для работы <b>в ограниченном пространстве</b>.</p>
<h3>В комплекте</h3>
<ul><li>два аккумулятора</li><li>зарядное устройство</li><li>кейс</li></ul>]]></description>
<categoryId>60</categoryId>
<vendor>Bosch</vendor>
<price>8990</price>
<param name="Тип аккумулятора">Li-Ion</param>
<param name="Наличие реверса">да</param>
<param name="Цвет">синий</param>
</offer>
<offer id="sku-102">
<name>Платье летнее хлопковое, синее, 44 размер</name>
<categoryId>30</categoryId>
<vendor>Zarina</vendor>
<price>2490</price>
<param name="Размер">44</param>
<param name="Цвет">синий</param>
</offer>
</offers>
</shop>
</yml_catalog>
- id (атрибут
<offer id="…">) — ваш идентификатор товара (он жеexternal_id), обязателен: без него сервис не создаст запись, а вернёт по этому товару ошибку «у товара нет id (в YML обязателен атрибут <offer id>)» вerrorsотчёта (раздел 5) — в намерение он не превратится. - categoryId — ссылка на категорию из дерева
<categories>; путь сервис собирает сам по вложенностиparentId. Категория — источник тегов и запасное название намерения на случай, когда из названия товара взять нечего: знакомую сервису категорию он переводит по словарю (лист «Дрели-шуруповёрты» → «дрель-шуруповёрт»), незнакомую — берёт по её имени. Товар без категории или с пустым именем категории пропускается (попадает вskippedотчёта, раздел 5, с причиной «пустая категория»). - name — обычное название товара из вашего каталога. Из него сервис берёт НАЗВАНИЕ намерения — одно-два значимых слова, то, что покупатель наберёт в своём «хочу купить» («Дрель-шуруповёрт Bosch GSR 12V-15…» → «дрель-шуруповёрт»). Полное название целиком становится первым абзацем описания намерения: модель и размер нужны покупателю, а в коротком названии намерения им нет места.
- description — описание товара, необязательно. Оно идёт в описание намерения следом за названием. Годится и обычный текст, и HTML — внутри
<![CDATA[ … ]]>, экранированный или просто тегами. Сохраняется оформление: абзацы и переносы, подзаголовки (<h1>–<h6>— одного уровня), списки, жирный и курсив; строки, начатые «- » или «• », тоже становятся пунктами списка. Ссылки остаются текстом без адреса, стили, цвета и размеры шрифта отбрасываются, картинки и скрипты удаляются целиком. Если описание уже начинается с названия товара, название второй раз не добавляется. Описание намерения вмещает 6000 символов — длиннее сокращается по границе абзаца, и это видно по счётчикуdesc_truncated(раздел 2). - vendor и param (характеристика в теге
<param name="…">…</param>) — становятся тегами намерения по внутреннему словарю, но только при ТОЧНОМ (без учёта регистра) совпадении имени характеристики со словарём: например, «Наличие реверса: да» → тег «с реверсом», а вот просто «Реверс: да» словарь не узнает по имени и молча отбросит. У каждого узнанного тега есть вес важности (зависит от категории товара, домена и самой характеристики), и в намерение он попадает, только если вес не ниже порога отсечения — например, «Цвет» у инструментов намеренно снижен (для подбора совпадений по дрели цвет не важен) и почти всегда отбрасывается, а у одежды, наоборот, входит в вес. В примере выше поэтому «Наличие реверса: да» у первого товара становится тегом «с реверсом», а «Цвет: синий» у него же — отбрасывается по весу; у второго товара (одежда) «Цвет: синий» тегом становится. Тегов на намерение остаётся немного (алгоритм подбора совпадений по тегам точнее работает с коротким набором самых важных, а не длинным списком характеристик). Отброшенное — не ошибка: агрегированную статистику (сколько раз и по какой причине) показывает полеmetrics.drop_reasonsотчёта (раздел 5); привязки «какой именно товар и характеристика» в отчёте нет — это сводка по всему фиду. - Страна в
vendorтегом не становится — она уходит в характеристики. В<vendor>полагается марка, но магазины часто пишут туда страну производства: в одной живой выгрузке «Россия» стояла у 11 422 товаров из 20 010. Марка — самый весомый источник тега, поэтому такое слово вставало первым и в тегах карточки, и в заголовке страницы в поиске, хотя у половины каталога оно одинаковое и ничего не различает. Теперь известные названия стран тегом не становятся, а показываются в блоке характеристик строкой «Страна производства» — покупателю она видна, подбору совпадений не мешает. Если у товара есть своя характеристика «Страна производства», берётся она. Правило касается только элемента<vendor>: слово «Россия» в названии товара или в значении характеристики сервис не трогает. Список стран ведёт оператор сервиса — встретили в выгрузке страну, которую сервис принял за марку, напишите нам. - vendorCode — артикул товара. Показывается на карточке намерения отдельной строкой «Артикул» сразу под названием и попадает в товарную разметку страницы как
sku. Берётся ДОСЛОВНО: регистр не меняется, ведущие нули сохраняются («008365» так и останется «008365»). Тегом артикул не становится — по нему не ищут зеркальные намерения, и в подборе совпадений он бесполезен. Артикула в выгрузке нет — строки на карточке просто не будет, ошибкой это не считается. Длиннее 64 символов — хвост обрезается, товар при этом не теряется.
Это НЕ то же самое, что атрибут id товара: id мы используем служебно, чтобы при следующей выгрузке обновить то же намерение, а не создать второе, и человеку он нигде не показывается. Если ваш артикул лежит не в <vendorCode>, а в характеристике <param name="Артикул">, он попадёт в блок «Характеристики» строкой, но в разметку как sku не пойдёт — выгрузку в этом случае лучше поправить.
- Теги собираются и из НАЗВАНИЯ товара — всегда, а не только когда характеристик нет (а в выгрузках магазинов их чаще всего и нет). Порядок такой: характеристики занимают места первыми, разбор названия ДОБИРАЕТ то, что осталось. Из названия берутся значимые слова, латинская марка и размеры. Размер понимается в трёх привычных формах:
8х 60→ тег8х60,М 14,0→м14,d 3иДу 20→d3иду20. Это важно для крепежа и сантехники: без размера сотни болтов выглядели бы для подбора совпадений одинаково. Артикул в начале названия («D 46 Колесо») тегом не становится — его никто не ищет. - Из названия отсеивается мусор. Разбор названия — машинный, и в него попадает то, что тегом быть не должно. Отсеиваются три вида: общее слово («упаковка», «длина», «покрытие», «размер» — список ведёт администратор сервиса и дополняет под выгрузку), одиночное число («1 000» из «(упаковка 1000шт.)» — искать его незачем) и обрубок размера («6,0х» — разделитель есть, второго числа нет). Составные обозначения при этом остаются: «8/256» у смартфона и «4х8» у крепежа — настоящие теги. Так в примере выше у платья тегами станут
р. 44исинийиз характеристик ихлопковое,синееиз названия, а слово «размер» из названия — нет: размер уже приехал характеристикой. Смысл отсева в том, что число тегов ограничено: пока слот занимает «упаковка», за предел уходит настоящая характеристика, и совпадение считается хуже. - Характеристики видны на карточке отдельным блоком (с 21.09.2026). Тег — не единственный выход характеристики: всё, что пришло в
<param>, попадает в блок «Характеристики» на странице намерения — именем и значением вашего магазина, в вашем порядке. Это важно, потому что тегов на намерение немного (так точнее считаются совпадения), и раньше характеристика, не ставшая тегом, для покупателя просто исчезала. Теперь у неё два выхода: тег — для подбора совпадений, блок — для человека. Что нужно знать:
- в блок НЕ попадают характеристики, уехавшие в поля намерения (количество и единица) — они уже показаны на карточке отдельно;
- служебные имена, которые не становятся тегами («Гарантия», «Страна производства», «Вес»), в блоке ЕСТЬ: покупателю они полезны, а хештегом быть не должны;
- одинаковые имена схлопываются, пустое имя или значение пропускается;
- сразу видны первые восемь, остальные раскрываются кнопкой «Показать все»;
- пределы: 30 характеристик на товар, 64 символа имя, 256 значение, 4 КБ на товар. Сверх предела хвост отбрасывается, но товар не теряется — число усечённых видно в отчёте прогона (
specs_truncated); - запрещённые слова в имени или значении маскируются, а не снимают товар.
Характеристики считаются содержимым страницы при решении, попадёт ли она в поиск: порог смотрит на описание вместе с ними. Это работает в вашу пользу — у однотипных товаров именно характеристики отличают одну карточку от другой.
- Товар без единого тега не пропадёт. Если после разбора тегов не нашлось (короткое название вроде «Засов гаражный», где оба слова ушли в название намерения), тегом станет слово самого названия. Раньше такой товар не импортировался вовсе с причиной «укажите хотя бы один тег»; теперь он публикуется, просто набор тегов у него беднее.
- Территория — только из профиля организации. YML город не несёт, поэтому сервис берёт город из профиля организации (раздел «Профиль» личного кабинета). Проще всего задать город один раз там — он подхватится для всех товаров. Если города в профиле нет, товар НЕ импортируется — в отчёте будет причина «не указан город»: при стандартных настройках «Вся страна» совпадает только со «Всей страной» (см. «Как это работает» → «Территория»), то есть импорт без города плодил бы намерения, не способные ни с кем совпасть.
- price — цена в рублях, необязательна (с 22.09.2026). Если цены в выгрузке нет, намерение публикуется со стоимостью «Договорная»: цену вы не назвали, значит она обсуждается. Раньше такой товар в сервис не попадал вовсе — он не проходил проверку «укажите стоимость или „договорная“» и уходил в
errorsотчёта. Цену сервис при этом не выдумывает ни при каких условиях: подставленное число уехало бы в подбор совпадений, в выдачу и в публичную карточку как настоящее.
Как записать число. Разделителем дробной части принимается и точка, и запятая: 1990.50 и 1990,50 читаются одинаково — русская локаль 1С пишет запятую, и это норма выгрузок, а не экзотика. Разделителем разрядов принимается пробел в любом из трёх написаний, встречающихся в выгрузках (обычный, неразрывный и узкий неразрывный), поэтому 1 234 567,89 разбирается целиком. А вот слова и единицы в поле цены класть нельзя: 1990 руб. числом не станет.
Непонятная запись цены считается отдельно — счётчиком price_bad (раздел 5), не смешиваясь с товарами, у которых цены нет вовсе. Такой товар тоже публикуется с «Договорной», но price_bad больше нуля означает, что цену вы назвали, а сервис её не понял, — это повод поправить выгрузку. Различать обязательно: иначе о потере цен на всём каталоге вы узнаете от покупателей.
Все загруженные товары становятся намерениями «Могу продать» — другие типы (аренда, услуги, вакансии) через этот канал сейчас недоступны. Состояние товара при импорте всегда «новое» — это не настраивается.
Характеристики товара
Характеристики из <param>, которые не ушли в количество и единицу, сервис сохраняет отдельно — как набор пар «имя — значение» в том порядке, в котором их отдал магазин. Имена и значения не переписываются: чужую номенклатуру мы к своей не приводим.
Это второй выход характеристики, помимо хештега. Тег — для подбора совпадений, и их немного по необходимости: алгоритм точнее работает с коротким набором самых важных. Характеристика — для человека, и резать её незачем. Поэтому в набор попадает и то, что тегом стать не может: гарантия, страна производства, вес — их блокирует список служебных имён для ТЕГОВ, а на сохранённые характеристики он не распространяется.
Что не попадает: характеристика, уехавшая в количество или единицу (она уже показана на карточке), пустое имя или значение, повтор имени (побеждает первое вхождение).
Лимиты: до 30 характеристик на товар, имя до 64 символов, значение до 256, набор целиком до 4 КБ. Сверх лимитов хвост отбрасывается, а длинные имя и значение обрезаются — товар при этом публикуется, а число таких товаров видно в отчёте импорта полем specs_truncated.
Стоп-слова по характеристикам проходят так же, как по описанию: найденное слово маскируется, товар не снимается. Снимать весь товар из-за слова в одной строке свойств несоразмерно.
В ответе API характеристики приходят полем specs намерения. Поле только для чтения: задать его запросом нельзя, единственный источник — ваш фид.
На карточке намерения характеристики видны отдельным блоком: на сайте — под фотографиями, в приложении — между тегами и описанием. Сразу показываются первые восемь, остальные раскрываются по кнопке. Если характеристик нет, блока нет совсем.
Количество и единица измерения
Количество сервис берёт из первого доступного источника:
- характеристика
<param>, чьё имя есть в словаре количества — по умолчанию «Доступное количество», «Количество в упаковке», «Кол-во в упаковке», «Количество на складе», «Остаток на складе» (регистр не важен; список пополняет администратор сервиса, поэтому своё название можно согласовать); - штатный элемент YML
<count>— остаток товара на складе.
Количество может быть дробным — «2,5» для погонных метров, «0,5» для килограммов. Разделителем принимается и запятая, и точка: 2,5 и 2.5 читаются одинаково. Хранится до трёх знаков после запятой, и если в выгрузке их больше, лишнее округляется: 2,5555 станет 2,556. Округляет сервис, а не база, поэтому ответ на запрос показывает ровно то число, которое легло в хранилище. Дробное количество принимается при любой единице измерения.
Единицу измерения — тоже из первого доступного:
- характеристика из словаря единиц: «Базовая единица», «Единица измерения», «Ед. изм»;
- атрибут
unitу характеристики количества —<param name="Количество в упаковке" unit="шт">200</param>; - суффикс после запятой в её имени — «Количество в упаковке, шт»;
- штатный элемент
<unit>внутри товара — например<unit>шт</unit>. Это резервный источник: он используется, только если единица не найдена в характеристиках выше.
Единица приводится к записи, принятой в сервисе («шт» → «шт.»), чтобы совпасть с набором единиц, который видит человек при правке намерения. Если количество нашлось, а единицы нет ни в одном из четырёх источников, подставляется первая единица набора вашей пары — та же, которую мастер предлагает человеку первой (набор настраивает оператор сервиса). Прежде тут стояло жёсткое «шт.», и после правки набора единиц подстановка давала бы единицу, которой у пары нет.
Единица нужна всегда, когда количество указано числом: намерение с количеством и без единицы сервис не публикует (ошибка поля unit). При «Неограничено» единицы нет вовсе — и она не требуется.
Единицей признаётся только то, что похоже на единицу: в значении должна быть хотя бы одна буква, и оно не длиннее 16 символов. Это не придирка — выгрузки кладут в это поле внутренний код единицы из учётной системы вместо её названия («736», «345»), и без проверки карточка читалась бы «, 3 736», то есть как число 3736. Цифра внутри единицы при этом законна: «м3» и «м2» принимаются — так пишут, когда надстрочного знака нет под рукой. Негодное значение видно в отчёте импорта с причиной «поле единицы измерения: «736» не похоже на единицу», количество при этом сохраняется, а единица подставляется по умолчанию. Если в отчёте таких строк много — поправьте выгрузку: сервис угадать настоящую единицу не может.
Пример выгрузки 1С-Битрикса, который сервис понимает целиком:
<param name="Базовая единица">шт</param>
<param name="Доступное количество">153</param>
Если количества в фиде нет вовсе, намерение публикуется с количеством «Неограничено»: магазин не называет число, но продать готов любое количество. Это НЕ то же самое, что «одна штука» — раньше подставлялась именно она, и подбор совпадений считал, что каждого товара у магазина по одной, из-за чего каталог не попадал к тем, кому нужна партия.
Характеристики, ушедшие в количество и единицу, тегами НЕ становятся — в сводке отчёта они видны как отброшенные с причиной «→ поле «количество» намерения».
4. Синхронизация и обновления
- id связывает запись файла с намерением в сервисе: повторная загрузка того же
idобновляет намерение на месте (без версий, как и везде в сервисе), а не создаёт дубль. - Товар, пропавший из очередного файла, сам по себе никак не меняется — намерение остаётся опубликованным. Чтобы такие товары закрывались автоматически, добавьте
remove_missing=1к запросу (push) или включите тумблер «Закрывать пропавшие из фида» (импорт по ссылке). - Файл без товаров мы не применяем. Если файл прочитался, но товаров в нём нет, загрузка отменяется целиком с ошибкой «фид не содержит товаров» — опубликованные намерения остаются на месте. Это защита от сбоя вашего сервера: отдай он пустой ответ или страницу ошибки, включённый флажок «Закрывать пропавшие из фида» снял бы с показа весь ваш каталог, а вернуть намерения в показ пришлось бы вручную по одному.
- Фотографии и видео, добавленные вручную, импорт больше не стирает (с 09.08.2026). Файл фида их не содержит и никогда не содержал, поэтому единственный способ показать фото у загруженного товара — добавить его самим. Раньше любая последующая загрузка с изменённой ценой или описанием снимала эти фото: сам файл в хранилище оставался, но переставал быть привязан к намерению. Теперь загрузка меняет только те поля, которые есть в файле.
- Загруженные намерения проходят те же проверки, что и созданные вручную: нормализация тегов, фильтр недопустимых слов, лимиты активных намерений — и публикуются сразу.
5. Ответ и коды
Отчёт о прогоне — один и тот же формат у прямого вызова и у «Проверить сейчас» (раздел 6), но они по-разному сообщают об отказе — это две разные вещи, их легко перепутать:
- Прямой вызов (
POST /v1/org/intentions/import) — обычный REST: успех —200с отчётом ниже, отказ — HTTP-код с текстом ошибки (коды — дальше в этом разделе). - «Проверить сейчас» (
POST /v1/org/feed/sync, раздел 6) отвечает200практически всегда, даже если сама синхронизация не удалась — из специально обрабатываемых исходов ответа два не 200, они описаны в разделе 6. Смотрите полеokиfeed.last_messageв теле ответа, а не HTTP-код.
Успешный прогон (прямой вызов) отвечает 200:
{
"shop": "Мой магазин",
"dry_run": false,
"counters": {
"total": 2, "created": 1, "updated": 1,
"unchanged": 0, "skipped": 0, "closed": 0, "errors": 0,
"revived": 0, "no_photo": 2,
"desc_truncated": 0, "specs_truncated": 0,
"feed_offers": 2, "unavailable": 0,
"photo_none": 2, "photo_one": 0, "photo_many": 0,
"price_from_feed": 2, "price_negotiable": 0, "price_bad": 0,
"quantity_from_feed": 0, "quantity_unlimited": 2
},
"skipped": [],
"errors": [],
"metrics": {
"total": 2, "converted": 2, "skipped": 0,
"category_hit_rate": 1, "avg_tags": 2.5,
"drop_reasons": { "вес 15 < порога 25": 1 }
},
"report": {
"v": 2,
"total": 2, "created": 1, "updated": 1,
"unchanged": 0, "skipped": 0, "closed": 0, "errors": 0,
"revived": 0, "no_photo": 2,
"desc_truncated": 0, "specs_truncated": 0,
"feed_offers": 2, "unavailable": 0,
"photo_none": 2, "photo_one": 0, "photo_many": 0,
"price_from_feed": 2, "price_negotiable": 0, "price_bad": 0,
"quantity_from_feed": 0, "quantity_unlimited": 2,
"dropped_reasons": [
{ "reason": "Вес 15 < порога 25", "count": 1 }
]
}
}
skipped[] — товары с пустой или незнакомой категорией (раздел 3), у каждой записи id товара и причина. errors[] — остальные отказы по товару: нет id, лимит намерений, недопустимое слово — тоже с id и текстом причины. Отсутствия цены среди них больше нет: с 22.09.2026 товар без цены публикуется с «Договорной» (раздел 3). metrics — сводка по ВСЕМУ фиду, не по отдельному товару: total/converted/skipped — всего офферов / распознано по категории / пропущено, category_hit_rate — доля распознанных категорий (converted/total), avg_tags — среднее число тегов на распознанный товар, drop_reasons — сколько раз и по какой причине отброшена ХАРАКТЕРИСТИКА при формировании тегов (раздел 3); привязки «какой товар» здесь нет — это агрегат для калибровки фида в целом, не диагностика конкретной позиции.
Поле report: тот же прогон, свёрнутый до отчёта
report появился 22.09.2026 и отвечает на вопросы, с которыми раньше приходилось идти в поддержку: куда делись позиции из выгрузки, почему часть товаров без фотографии, что именно не доехало. counters, skipped, errors и metrics при этом остались как были — прежние интеграции ничего не замечают.
- Версия формата —
v(сейчас2). У записей, сделанных до 22.09.2026, поля нет вовсе. - Счётчики лежат на верхнем уровне
report: те же ключи, что вcounters, плюс ничего сверх. Дублирование намеренное — отчёт ложится в статус фида целиком (раздел 6), и читать его там должно быть можно без второго объекта. - Свойства выгрузки описывают ваш файл, а не исход импорта, и считаются до разбора, поэтому товар, который дальше отвалится, в них всё равно учтён:
feed_offers— позиций в файле (принятые плюс отсеянные поavailable="false");unavailable— сколько отсеяно;photo_none,photo_one,photo_many— распределение товаров по числу тегов<picture>(сумма трёх равнаtotal);price_from_feed,price_negotiable,price_bad— откуда взялась стоимость (раздел 3);quantity_from_feed,quantity_unlimited— то же для количества. - Сумма
quantity_from_feedиquantity_unlimitedравнаtotalминусskipped, а неtotal: количество — свойство разбора характеристик, и у товара, пропущенного конвейером, характеристики не читались. Записать пропущенные в «Неограничено» ради красивой суммы значило бы соврать о том, чего мы не считали. - Причины — видами, а не списком товаров.
error_reasons(товар в сервис не попал),skipped_reasons(пропущен конвейером) иdropped_reasons(отброшены отдельные ХАРАКТЕРИСТИКИ — сами товары при этом опубликованы, и числа здесь самые крупные в отчёте). У каждого вида —reason,countи до трёхexamplesсidтоваров: по примеру позиция ищется в выгрузке руками, а счётчик отвечает, чинить выгрузку или ждать. Списка на двадцать тысяч позиций здесь нет намеренно: отказ обычно один и тот же на сотнях товаров, и список — это полтора мегабайта JSON без единого ответа на вопрос «что чинить». Пустых видов в отчёте нет — ключ просто отсутствует. - Итог переноса фотографий —
photosвида{"moved": 5142, "failed": 12, "at": "2026-09-22T11:04:19Z"}. Дописывается в отчёт ПОЗЖЕ самого прогона: перенос идёт фоном до двух часов после ответа, и в момент, когда отчёт готов, фотографий может не быть ещё ни одной — пока перенос идёт, ключа нет.movedсчитает ФАЙЛЫ, а не товары: одна картинка нередко стоит у нескольких позиций.
Коды прямого вызова:
401— токен не передан, отозван или неверен.403— аккаунт организации заблокирован либо тарифный план не оплачен (доступ по API приостановлен).409— либо пара «Хочу купить» / «Могу продать» временно отключена администрацией сервиса, либо импорт вашего фида уже выполняется (вы отправили два файла разом, или в этот момент сработал импорт по ссылке из раздела 6). Точная причина — в тексте ошибки. В обоих случаях повторите позже: прогоны одной ссылки идут строго по очереди, иначе они мешали бы друг другу — в частности, прогон со старым файлом снял бы с публикации товары, которые только что добавил прогон со свежим. Другая ссылка той же организации может обновляться одновременно. Без параметраfeed_idпрямой вызов пишет в самую раннюю ссылку; чтобы обновить другую, передайте еёfeed_id.413— файл больше действующего предела размера.422— файл не похож на YML Яндекс.Маркета (нет XML-корняyml_catalog, битый синтаксис, вообще не XML) — не путать сskipped/errorsотдельного товара внутри валидного файла.
6. Импорт по ссылке (pull)
Альтернатива прямому вызову — без токена и без запросов с вашей стороны. В блоке «Импорт по ссылке» (пилюля «Каталог») можно указать несколько URL (тот же формат, что в разделе 3). У каждой ссылки свой прогон, свой тумблер «Закрывать пропавшие из фида» и свой отчёт: товары одной ссылки не снимаются прогоном другой. Сервис сам периодически скачивает каждую ссылку. Потолок — 20 ссылок. Повтор того же адреса не сохраняется. «Убрать ссылку» останавливает поставку этой выгрузки, карточка остаётся, пока намерения не сняты.
- Тумблер «Обновлять автоматически» включает периодическую выкачку; частоту (по умолчанию раз в 6 часов) настраивает поддержка сервиса.
- Тумблер «Закрывать пропавшие из фида» — то же самое, что
remove_missingу прямого вызова, но для pull-режима. - Кнопка «Проверить сейчас» запускает синхронизацию немедленно. Ответ практически всегда
200вида{ "ok": true|false, "feed": {...} }— сам HTTP-код не сигнализирует об отказе (в отличие от прямого вызова, раздел 5): любая ошибка синхронизации (не выкачался файл, файл не YML, отключена пара, не оплачен тариф и т. д.) — этоok: falseи человекочитаемый текст вfeed.last_message, а не отдельный HTTP-код. Исключений два:422, если ссылка на фид ещё не сохранена (сначала заполните и сохраните поле URL), и409, если импорт вашего фида в этот момент уже идёт (например, вы одновременно отправили файл напрямую) — тогда статус фида не меняется, просто дождитесь завершения. При удачеfeed.last_countersсодержит отчёт о прогоне целиком — то же самое, что полеreportпрямого вызова (раздел 5), со счётчиками на верхнем уровне объекта. Неудача выкачки этот отчёт не стирает: вlast_message— текст ошибки, аlast_countersостаётся от последнего успешного прогона этой ссылки. Ход идущего прогона читается по конкретной ссылке:GET /v1/org/feeds/{id}/progress. - Ссылка должна быть публичной (обычный http/https, без входа) — сервис не проходит авторизацию на стороне вашего файлового хранилища.
Ход идущего прогона
Прогон крупного файла идёт до полутора-двух минут. Чтобы всё это время было видно, что работа движется, есть отдельная ручка GET /v1/org/feed/progress (с 22.09.2026, обычная сессия личного кабинета — токен здесь не участвует). Прогон остался СИНХРОННЫМ: POST /v1/org/feed/sync по-прежнему отвечает 200 с отчётом, контракт не менялся. Ручку хода опрашивают ПАРАЛЛЕЛЬНО с идущим запросом, раз в 1–1,5 секунды.
{
"running": true,
"phase": "import",
"determinate": true,
"done": 12400,
"total": 19867,
"started_at": "2026-09-22T11:02:41Z",
"counters": {
"total": 19867, "created": 208, "updated": 11021,
"unchanged": 1100, "skipped": 0, "closed": 0, "errors": 71,
"revived": 0, "no_photo": 65,
"desc_truncated": 0, "specs_truncated": 0,
"feed_offers": 21480, "unavailable": 1613,
"photo_none": 65, "photo_one": 4100, "photo_many": 8235,
"price_from_feed": 12398, "price_negotiable": 2, "price_bad": 2,
"quantity_from_feed": 12400, "quantity_unlimited": 0
}
}
phase—download(выкачиваем файл по ссылке),parse(разбираем YML),import(создаём и обновляем намерения),close(снимаем пропавшие из выгрузки).determinate— у фазы есть честная доля, и она есть ТОЛЬКО уimport: разбор двадцати тысяч товаров занимает около 0,7 секунды, а всё остальное время прогона — запись в базу. У выкачки и разбора процентов нет и взять их неоткуда (Content-Lengthмагазины отдают не всегда, а на сжатом файле он к тому же не о том объёме), поэтомуdoneиtotalтам отсутствуют вовсе: доля, посчитанная не по реальной работе, — выдуманное число на экране.counters— что насчиталось к этому моменту, теми же ключами, что в отчёте. Именно они отвечают на вопрос «работает или висит»: доля может стоять на тяжёлом товаре, а числа растут.scheduled: true— прогон начат по расписанию, а не вами. Раньше такие прогоны шли совершенно незаметно, и «Проверить сейчас» в этот момент отвечал409без объяснения.- Прогона нет — ответ
200сrunning: false, а не404: ручку опрашивают в цикле, и ошибка на каждом такте засоряла бы и журнал, и консоль браузера. - Сухой прогон (
dry_run) хода не пишет: он ничего не создаёт, а фаза называется «создаю намерения».
7. Ограничения
- Размер файла — по умолчанию не больше 60 МБ, товаров в файле — не больше 60 000. Оба предела настраиваются оператором сервиса, поэтому текущие значения уточняйте в поддержке; при превышении приходит
413с указанием предела. - Территория — по справочнику ФИАС/DaData (регион, город, адрес до дома) или «вся страна».
- Крупный файл обрабатывается не мгновенно: само чтение файла быстрое (около полусекунды на 20 тысяч товаров), но дальше каждый товар проходит проверки и запись, и это занимает время — до полутора-двух минут на большой каталог. Это ожидаемо, не сбой.
- При слишком частых запросах сервис может ответить
429— это защита от перегрузки; сделайте паузу и повторите позже. Для регулярной синхронизации предпочтительнее импорт по ссылке (раздел 6) с разумным интервалом, а не непрерывные повторы вручную. - Матчинг, статусы и остальные лимиты — целиком на стороне сервиса; файл задаёт только исходные данные товара.
Оба способа уже доступны без ожидания — не нужно ничего согласовывать заранее: выпустите ключ или укажите ссылку на файл в личном кабинете организации, разделы «Подключение по API» и «Импорт по ссылке». Вопросы по формату или подключению — в чат «Идеи и предложения» (первый в списке ваших чатов) или на почту поддержки.
Если вы перестали поставлять фид
Убрали ссылку или выключили фид — сервис считает это остановкой поставки. Ваши намерения из этого фида останутся в выдаче на срок отсрочки (по умолчанию неделю), а потом будут сняты с публикации. Точную дату вы увидите в личном кабинете, в блоке «Импорт по ссылке», и получите уведомление в момент остановки.
Почему так: после остановки цены и наличие в ваших намерениях никто не обновляет, и люди находят карточки, которым нельзя верить.
Три вещи, которые стоит знать:
- это обратимо. Вернули ссылку и включили фид до истечения срока — снятие отменяется, ничего делать не нужно;
- намерения не удаляются, а снимаются. История и диалоги сохраняются; чтобы вернуть их в выдачу позже, укажите ссылку и запустите импорт;
- намерения, созданные вами вручную, не трогаются. Правило касается только того, что пришло из фида.
Если вы просто меняете адрес фида — недели с запасом хватает, и делать ничего не надо.
API наличия по точкам
Эти маршруты принимают ключ организации Bearer nmr_org_… либо JWT владельца организации:
GET /v1/org/inventory/sources— список{sources:[...]};PUT /v1/org/inventory/sources— один источник{id,kind,catalog_namespace,location_id,yml_profile,channels,enabled};GET /v1/org/inventory— активныеlocations,offers,pools,delivery_rules,bindings,sources,revision;POST /v1/org/inventory/import?feed_id=ID&dry_run=1— проверка JSON или YML настроенного источника. После проверки уберитеdry_run.
Для API-источника используйте kind:"api", без URL. Для YML укажите kind:"yml" и явный профиль kit, market или merchants. ID обычного планового фида можно использовать как ID источника. catalog_namespace объединяет одинаковые SKU нескольких явно настроенных источников одной организации; без него источники независимы. Менять namespace с готовыми привязками нельзя.
Пример подготовки магазина:
{
"schema_version": 1,
"request_id": "locations-1",
"revision": 1,
"mode": "delta",
"channels": ["locations"],
"locations": [{
"external_id": "A", "name": "Магазин А", "kind": "retail",
"geography": {"country": "RU", "city_fias_id": "ПРОВЕРЕННЫЙ-КОД", "city": "Москва"},
"address": "Москва, Тверская улица, дом 1",
"active": true, "pickup_enabled": true, "shipping_enabled": true
}]
}
Источник должен владеть каналом locations. Для KIT внешний ID совпадает с ID склада из файла; названия складов сами по себе не заменяют проверенную географию. Для обычного YML сохраните полученный ID точки в поле location_id источника. Рабочий XML можно загрузить в тот же import-маршрут. Каталог и наличие активируются вместе; ошибочный снимок не оставляет частично опубликованные товары.
JSON наличия использует уже созданные карточки. Массив bindings содержит {external_id,intention_id,product_key}; разрешены только ваши карточки «Могу продать». Предложение содержит product_external_id, location_external_id, unit, currency, stock_pool_key, quantity, stock_state, available, pickup_allowed, delivery_allowed, price, price_state. Decimal-поля передавайте строками. stock_state: known, unknown, unlimited, out_of_stock; price_state: known, unknown.
Каналы stock, prices, locations, delivery независимы. Например, JSON-пакет только prices не изменяет количество из YML. В другом источнике цен явно настройте общий namespace, собственную привязку SKU к той же карточке и используйте сохранённый ID общей точки. Повторная запись канала предложения другим писателем возвращает 409.
Для доставки используйте delivery_rules: source_location_id, destination_type (city, region, country), destination_fias_id или country, enabled, effect (allow, deny), service_code, days_min, days_max, days_kind, cost_state, cost. Стоимость относится к отдельному отправлению; неизвестная стоимость не означает бесплатную доставку. Адрес закрытого склада не становится адресом визита.
Успешный отчёт: {inventory_revision,replayed,dry_run,offers,locations}. GET inventory.revision + 1 подходит как следующая ревизия ручного изменения. Повтор request_id с изменённым содержимым и старая ревизия канала возвращают 409; неизвестные ссылки и невалидный снимок не меняют активные данные. Пустой снимок stock требует confirm_empty:true. Snapshot отключает только пропавшие предложения своего источника; delta сохраняет непереданные поля.
В режиме точек остановка источника выключает его предложения после установленной отсрочки. Карточки, URL и диалоги сохраняются; карточка, закрытая человеком, автоматически не публикуется заново. Это отличается от описанного выше поведения старого режима legacy.
Повтор явного JSON request_id только возвращает прежний результат и не подтверждает остатки заново. У YML без надёжной версии новый успешный приём неизменившегося текущего файла подтверждает свежесть без повторных событий. Последовательность A → B → A допустима: без версии нельзя отличить старый файл от возвращения остатка 2 → 0 → 2; такие приёмы сериализуются и получают новую серверную ревизию. Более старая достоверно датированная версия отклоняется. Дата без смещения используется только с явно настроенным часовым поясом источника или его единственной точки. Для просрочки берётся более раннее из времени поставщика и подтверждения. Серверные last_received_at, active_payload_hashes, supply_stopped нельзя подменить настройкой источника.
Настройка и проверка источника
На сайте: Кабинет → Каталог → Магазины, склады и доставка. Выберите существующую выгрузку по ссылке и нажмите «Проверить выгрузку». Предпросмотр покажет полученные магазины и склады. Если сведений достаточно, нажмите «Подключить магазины из выгрузки». Вручную вводить ID фида или создавать точки из полного файла не требуется. Повторное подключение обновляет те же точки и карточки. Плановые прогоны этой ссылки используют тот же импорт.
При неполных данных кнопка «Дополнить данные» предлагает только недостающие название, адрес или подтверждённый город. Изменённый после проверки файл требует новой проверки. Выключенную выгрузку сначала включите в «Импорте по ссылке». Для API и старых профилей сохранён раздел «API, доставка и ручные настройки». В мобильном приложении остаётся прежняя кнопка «Источники, точки и наличие».
Сухой прогон YML может вернуть discovered_locations и issues с перечнем точек, которым нужна настройка. При dry_run=1 это 200 без применения; попытка применить такой файл до настройки — 422. Настройте географию, адреса и способы получения и повторите проверку. У обычного YML точка указывается полем location_id источника, а профиль KIT различает склады по их ID.
YML Маркета с магазинами, адресами, ценами и остатками
Основа — XML-формат YML Яндекс Маркета. Дополнительные элементы принадлежат расширению ХочуМогу v1, а не стандарту Яндекса. Объявите xmlns:hmg="urn:hochumogu:inventory:1" в корне; название префикса может отличаться, важен точный URI. Не смешивайте расширение с warehouses/stock профиля KIT.
<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2026-10-23T09:00:00+03:00" xmlns:hmg="urn:hochumogu:inventory:1">
<shop>
<name>Дом и ремонт</name><company>ООО Дом и ремонт</company>
<url>https://shop.example.ru</url>
<currencies><currency id="RUR" rate="1"/></currencies>
<categories><category id="1">Дрели</category></categories>
<pickup>true</pickup><delivery>true</delivery>
<hmg:locations>
<hmg:location id="msk-shop">
<hmg:name>Магазин на Тверской</hmg:name><hmg:kind>retail</hmg:kind>
<hmg:city>Москва</hmg:city>
<hmg:city-fias-id>0c5b2444-70a0-4932-980c-b4dc0d3f02b5</hmg:city-fias-id>
<hmg:address>Тверская улица, 1</hmg:address><hmg:pickup>true</hmg:pickup>
</hmg:location>
<hmg:location id="kzn-stock">
<hmg:name>Склад Казань</hmg:name><hmg:kind>warehouse</hmg:kind>
<hmg:city>Казань</hmg:city>
<hmg:city-fias-id>93b3df57-4c89-44df-bc7c-f7baf0f3f0ad</hmg:city-fias-id>
<hmg:address>Складская улица, 10</hmg:address>
<hmg:pickup>false</hmg:pickup><hmg:delivery>true</hmg:delivery>
</hmg:location>
</hmg:locations>
<hmg:delivery-rules>
<hmg:rule id="kzn-msk" location-id="kzn-stock">
<hmg:destination-type>city</hmg:destination-type>
<hmg:destination-fias-id>0c5b2444-70a0-4932-980c-b4dc0d3f02b5</hmg:destination-fias-id>
<hmg:days-min>2</hmg:days-min><hmg:days-max>4</hmg:days-max><hmg:cost>600</hmg:cost>
</hmg:rule>
</hmg:delivery-rules>
<offers>
<offer id="drill-100" available="true">
<url>https://shop.example.ru/drill-100</url>
<price>1000</price><currencyId>RUR</currencyId><categoryId>1</categoryId>
<name>Дрель электрическая Д100</name><description>Мощность 500 Вт.</description>
<hmg:availability>
<hmg:stock location-id="msk-shop"><hmg:quantity>2</hmg:quantity><hmg:price>1000</hmg:price></hmg:stock>
<hmg:stock location-id="kzn-stock"><hmg:quantity>5</hmg:quantity><hmg:price>900</hmg:price></hmg:stock>
</hmg:availability>
</offer>
</offers>
</shop>
</yml_catalog>
Это синтетический пример, адреса и товар вымышлены. Для изменённого снимка обновляйте date; рекомендуется ISO 8601 с часовым смещением.
| Элемент | Значение и правила |
|---|---|
shop/hmg:locations/hmg:location@id | Постоянный внешний ID точки внутри выбранной выгрузки; имя и адрес могут меняться без нового ID. |
hmg:name, hmg:kind | Название; retail (по умолчанию для новой точки) или warehouse. Закрытый склад не разрешает самовывоз. |
hmg:country, hmg:city | Страна (для новой точки RU) и название населённого пункта. |
hmg:city-fias-id, hmg:settlement-fias-id, hmg:region-fias-id | Коды ФИАС. Для города — city, для посёлка — settlement; region нужен для региональных маршрутов. Если код не передан, сервис пытается однозначно определить город по точному названию. При неоднозначности или недоступности подсказок потребуется выбор города в кабинете. Название склада не используется для угадывания города. |
hmg:address, hmg:timezone | Адрес торговой точки обязателен для самовывоза; IANA timezone, например Europe/Moscow. Адрес склада хранится, но покупателю для посещения не показывается. |
hmg:active, hmg:pickup, hmg:delivery | true/false или 1/0. Для новой точки: active=true, pickup=true для магазина / false для склада, delivery=false. |
offer/hmg:availability/hmg:stock@location-id | Ссылка на точку из hmg:locations; каждый offer обязан содержать hmg:availability, допустим пустой блок. Одна строка на точку. |
hmg:quantity | Неотрицательное количество, до трёх знаков после точки. Нет элемента — количество неизвестно; 0 — нет в наличии. Общий count не прибавляется к этим остаткам. |
hmg:price | Положительная цена за единицу, до двух знаков после точки, в валюте offer. Если нет — используется обычный offer/price. |
stock/hmg:pickup, stock/hmg:delivery | Переопределение способов получения товара. Не могут включить способ, запрещённый самой точкой; available=false выключает предложение. |
У hmg:delivery-rules/hmg:rule обязательны постоянный id, атрибут location-id, поля destination-type (city, region, country), целевой destination-fias-id для города/региона, days-min, days-max. Дополнительные поля: country (RU), enabled (true), effect (allow/deny, по умолчанию allow), service-code (courier), days-kind (calendar/working, по умолчанию calendar), cost, order-before, timezone. Нет cost — стоимость неизвестна, не бесплатна. Тариф доставки показывается отдельно и не входит в сравнение цены товара с бюджетом намерения. Само <delivery>true> географию доставки не создаёт.
Непустые значения файла имеют приоритет над ручными дополнениями; отсутствующие поля сохраняют прежние значения точки, кроме active: присутствие точки в полном справочнике означает active=true, если явно не передан false. Поэтому исчезнувшая и вернувшаяся точка снова работает. Пустые текстовые имя/адрес/коды можно дополнить при проверке. Ложные флаги из файла не заменяются значениями по умолчанию. Файл — полный снимок: исчезнувшие точки отключаются, отсутствующие строки наличия снимаются. Блок delivery-rules, если передан, заменяет правила этого источника; пустой блок очищает их, отсутствие блока сохраняет правила ручной настройки. Неизвестные ссылки, дубликаты ID, отрицательные количества, невалидные цены или версия расширения отклоняют снимок целиком, сохраняя активные данные.
Кабинет использует POST /v1/org/feeds/{id}/inventory/preview и …/connect с JWT владельца (не API-ключом организации). Тело {}; для дополнений — {"locations":[{"external_id":"msk-shop","address":"Тверская, 1"}]}. Предпросмотр возвращает feed_id, connected, ready, format, payload_hash и report.discovered_locations с location, needs_setup, missing_fields. В connect передавайте payload_hash из preview: если файл изменился, ответ 409. Preview ничего не сохраняет; connect сохраняет источник и весь снимок атомарно.
Для серверной интеграции можно по-прежнему настроить YML-источник с профилем market и каналами locations,stock,prices,delivery, затем отправлять такой XML через API-ключ организации:
curl -X POST 'https://api.hochumogu.ru/v1/org/inventory/import?feed_id=SOURCE_ID' \
-H "Authorization: Bearer $ORG_API_KEY" \
-H 'Content-Type: application/xml' \
--data-binary @feed-market-locations.xml
Обычный YML без расширения сохраняет прежнюю привязку к одной точке. KIT остаётся отдельным профилем: его складские названия не содержат подтверждённых адресов.
Конверт JSON содержит schema_version:1, уникальный request_id, возрастающую revision, mode (snapshot или delta), список channels и соответствующие массивы bindings, locations, offers, delivery_rules. pools в GET — рассчитанное состояние общих остатков; отдельный массив pools во входном JSON не передаётся. Предложения одного физического остатка связываются общим stock_pool_key, чтобы не посчитать этот запас дважды. Неизвестные остатки не становятся неограниченными: для этого есть явный stock_state:"unlimited".
При включённом контроле срока обновления старые остатки не участвуют в плане. Предел inventory_stale_after_hours настраивает сервис; значение 0 выключает эту проверку. Обновление только канала prices свежесть остатка не подтверждает.
Как покупатель получает план
Публичный запрос:
GET /v1/intentions/{id}/availability?country=RU&city_fias_id=ID_ГОРОДА&mode=delivery&quantity=5
X-Inventory-Version: 1
Укажите реальный код города из подсказок; для посёлка используется settlement_fias_id, для региональных правил доставки — также region_fias_id. mode — pickup, delivery или any, quantity — положительная decimal-строка до трёх знаков после точки. Передавайте заголовок X-Inventory-Version: 1 и в запросах карточек, совпадений и условий чата, чтобы клиент объявлял поддержку нового формата.
Ответ — {plans:[...], requires_destination:...} с Cache-Control: no-store. Без конкретного места доставки сервис требует его выбрать; текст city не заменяет ФИАС-код. Пустой plans означает, что доступного плана для этих условий нет. У неактивной карточки или замороженной организации планов также не будет.
Каждый план содержит requested_quantity, available_quantity, covered_quantity, partial, lines, shipments, goods_total, effective_unit_price, shipping_cost_state и inventory_revision. Самовывоз собирается из точек одного города; доставка может состоять из нескольких отправлений. Стоимость доставки считается за отправление. shipping_total и landed_total появляются только при известной стоимости всех отправлений. Неизвестная доставка не равна нулю.
Цена для подбора — средняя цена выделенного товара, без доставки. Частичный план разрешён и явно помечен. Карточка locations не имеет одной общей цены и территории на все случаи: используйте план конкретного города, количества и способа получения. В начале чата план сохраняется в слепке условий. Просмотр плана не резервирует товар, не создаёт заказ и не проводит оплату.