Vizen catalogue import via the API
/docs/catalog-importcurrentМашинный перевод с английского
Путеводитель для одного external разработчик или AI агент, заполняющий shop с products Использование персонального токена доступа (PAT).
Брат и сестра document /docs/webcoding покрытие page layout. Этот покрывает data: categories, products, images, attributes, variants связанный products. Полный schema: /openapi.json.
Это document Основан на обзоре реального import: "Каждая ошибка"" section Это ошибка, которая уже стоила кому-то переделки..
Тридцать секунд: что нужно знать before тот first запросить
| Факт | Последствия |
|---|---|
| The shop определяется в key, Не является параметром | company_id В запросе есть ignored; Другие жильцы невидимы |
| Цена является целым числом в shop currency | price.currency правила: Каталог § 8; Несоответствие отклоняется |
| А. key Пишет либо в live site или в том, draft | Имущество, которое key; нет header переключать его |
category_id Это первичный category, categories[] есть дополнительный один | Не повторяйте первичный в categories[] |
| Галерея является отдельной shop resource, не product field | Создан в /galleries; products, categories Статьи ссылаются на него через gallery_ids[] (§7) |
| Списки требуют оба части аббревиатуры | page.limit без page.number → 400 |
Каталог живет без тот /v1 prefix | /products, /categories; files и организация находится под /v1 |
1 шаг 0 — это key паспорт (обязательный))
GET /v1/account/token
Authorization: Bearer vz_pat_…{
"company_id": 7,
"contour": "prod",
"writes_to_live": true,
"dev_header_allowed": false,
"publish_allowed": false,
"expires_at": null,
"scopes": ["catalog:read", "catalog:write", "storage:read", "storage:write"],
"store": {
"name": "promo",
"slug": "promo",
"storefront_url": "https://promo.vizen.shop",
"currency": "USD",
"language": "ru",
"custom_domain": ""
},
"capabilities": {
"catalog_read": true, "catalog_write": true,
"storage_read": true, "storage_write": true,
"publish_dev": false, "store_settings_write": false
},
"warnings": [
"Ключ пишет в ЖИВОЙ магазин: изменения видны посетителям сразу…",
"Цена товара — целое число в валюте магазина (USD)…",
"Сменить валюту, язык или название магазина этим ключом НЕЛЬЗЯ…"
]
}Что с ним делать before Огромный текст:
writes_to_live: true→ Скажи owner явно: *"Посетители увидят, что немедленно"* — Ждать подтверждения.store.currency→ compare с помощью price список currency. Если они отличаются, остановиться. The owner изменениях, currency в admin панель; а key cannot (capabilities.store_settings_write: false).capabilities→ Проверьте, что required права, которые имеются. актуальный scope Это не означает, что метод открыт для key: тотcapabilitiesСписок вычисляется с фактической карты доступа, поэтому доверяйте ему..warnings→ Передайте их в owner в full, без перефразирования.
ловушка. The contour когда-то был обнаружен судом: написать product и идти look Это больше не нужно и не должно быть done.
2. Пять правил, которые нарушают импорт чаще всего
2.1. shop currency Переопределяет тот, который вы посылаете
Цена является целым числом в shop currency: 6400 6400 единиц, а не центы. The price.currency договором, описанным в /docs/catalogue §8: a empty value Допускается; не-empty несоответствие возвратов 400 CURRENCY_IS_STORE_LEVEL. Проверь. price список currency против key паспорт before импортировать; там Не является конверсией.
2.2. Начало - обе части или ни одна
GET /products?page.limit=100 → 400 (Number must be >= 1)
GET /products?page.limit=100&page.number=1 → 200
GET /products → 200 (default page)Если ты пройдешь page.limit, Вы также должны пройти page.number (нумерация начинается в 1).
2.3 Первичные и дополнительные categories различны fields
| Поле | значение |
|---|---|
category_id | первичный category. Определяет product's main URL и его перечень |
categories[] | Дополнительный categories (ids). The product Также появляется в них |
categories_replace: true | Нужно только очистить: [] + Флаг удаляет все дополнительные category. Неполный список заменяет set с или без него |
Ты не нужно Повторить первичный category в categories[] — это Создает избыточный link Вместо того, чтобы «укреплять» задание.
// create — primary only
POST /products { "item": { "category_id": 85 } }
// create — primary + two additional
POST /products { "item": { "category_id": 85, "categories": [86, 87] } }
// update — full replacement of additional ones
PUT /products/808 { "item": { "categories": [86, 87], "categories_replace": true } }
// update — clear additional ones, keep the primary
PUT /products/808 { "item": { "categories": [], "categories_replace": true } }Обновление A Non-Pempty categories заменять дополнительное set — делает Не прибавлять к нему. category, читать product и отправить весь список (измерено 2026-10-28: [86, 87] затем {"categories":[88]} листья [88]). Ан Пустой массив без categories_replace означает «не меняйся»; с флагом это Проясняет set. На создание флага не требуется.
2.4 Флаги трех государств - это нити, а не булевы флаги
Некоторые переключатели inherit от shop, У них есть три страны и они приезжают в JSON как струна:
| Поле | ценности | значение |
|---|---|---|
catalog_hidden | "" / "true" / "false" | "" и "false" — показанный; "true" — hidden из витрины магазина, поиска и подсчета разделов, карта по-прежнему открывается по своему адресу. PUT /products/{id} только: POST /products игнорировать его |
comments_enabled, questions_enabled | "" / "true" / "false" | то же самое |
reviews_scope | "" / own / category / shop / off |
is_published является регулярной булевый. Не смешивайте их: catalog_hidden: false (Булеан - это type error; Используйте струну "false", или "" перезагрузить.
Безопасная последовательность: создавать product с is_published: false → проверить читать → publish.
2.5. Category order это set Двигаясь, а не field
order В создании body это ignored: а new category always идти LAST Среди его братьев и сестер. value Вы читаете обратно, поэтому законно отличается от Тот, кого вы послали, не относитесь к этому как к error Не пытайтесь «заставить» number С другой стороны, писать.
Это держит положение брата и сестры плотным 0..n-1 set без дубликатов, которые before/after move Арифметика опирается на. field когда-то хранился как Отправлено, и каталог быстро накопился groups где каждый ребенок имел order = 0 — order Тогда было принято решение о внутренней id, и перетаскивание-drop из sections в admin панель перестала работать.
Если вам нужен конкретный order, set явно after Создавая все sections:
POST /categories/move
{ "from_id": "85", "to_id": "86", "type": "before" } // before | after | inside3. Каталог model
Shop (key)
├── Gallery (named media set; its own endpoint /galleries)
│ ↑ referenced by product, category, article and variant set
└── Category (storefront section; tree via parent_id)
└── Product ── primary category + additional ones
├── Attributes (attribute values: material, country, …)
├── Variants within the product (one card, switchers)
└── Grouping membership (several cards linked by axes)Галерея не принадлежать в product: существует на его own, и тот же самый Галерея может быть размещена на нескольких products, а category и ан article сразу. Это то, что standard «Take the Gallery from Another» (Возьми галерею у другого) product" (§7).
Ан атрибут (/attributes) это shop-Широкий словарь: code, type, widget, список options. Используется как в качестве характеристики, так и в качестве переключателя. ось.
4. Варианты или связанные products: Как выбрать
Платформа поддерживает оба Выбор сделан один раз и дорого обходится изменение — compare Используя стол.
| нужда | Варианты внутри a product | Группировка отдельных products |
|---|---|---|
| отдельно URL в комбинации | ✗ один URL + параметр | ✓ У каждого есть свой own |
| отдельно SEO титулов и description | ✗ | ✓ |
| Отдельная галерея для комбинации | ✓ set Ссылка на галерею (gallery_id, §5 шаг 4b) | ✓ У каждого есть свой own set из galleries |
| собственный SKU и price | ✓ | ✓ |
| Отдельные запасы level | ✓ | ✓ |
| отдельно card в каталожной сетке | ✗ один | ✓ каждый (extra Они являются hidden с catalog_hidden) |
| Стоимость установки | ниже: 1 product + sets | выше: N products + а group |
Выбор в одном line: только price, SKU и запасы различаются → variants; Фотографии тоже отличаются → variants + галерея на set; text, URL или position в Каталоговая сеть отличается → группирование.
"Другой цвет" может быть показан тремя способами, и они не заменяют друг друга.:
| Если вам нужно… | Механизм | Где это написано | Стоимость |
|---|---|---|---|
| другой чип и cart-line photo для variant, общий слайд | set image image_id | PUT /products/{id}/variants | один image за set |
| Различные фотографии в слайдере когда variant это selected, один product, один URL | галерея + set gallery_id | POST /galleries → PUT /products/{id} → PUT /products/{id}/variants | ≤15 galleries на объект × ≤24 items; делиться SEO |
| каждый variant иметь его own URL, SEO, description и сетка card | product группирование | Н. × POST /products + /product-groups | Н. products поддерживать; extra cards hidden с catalog_hidden |
image_id и gallery_id есть независимый set fields: тот first контроль чип и его cart line, Второй только слайдер.
Для промежуточных случаев (необходимы отдельные URL-адреса, но идентичные) content), использовать группировать: добавлять content Дешевле, потом разбиваешь product В девяти случаях не.
5 Сценарий А — один product с variants
Когда: Футболка в три раза sizes, Различаться только в price и запас.
# 1) Dictionary: axis attribute with options
POST /attributes
{ "item": {
"code": "size", "name": "Размер",
"data_type": "select", # a switcher axis is always select
"widget": "select", # text | select | icon | swatch | photo
"options": [ { "value": "s", "label": "S" },
{ "value": "m", "label": "M" },
{ "value": "l", "label": "L" } ] } }
# → result.id = 12, options have their own ids
# 2) Product
POST /products
{ "item": { "name": "Футболка TERRA", "category_id": 85,
"price": { "price": 2400 }, "sku": "TERRA-TSHIRT",
"is_published": false } }
# → result.id = 900
# 3) Product axes (replace-set)
PUT /products/900/variant-axes
{ "items": [ { "attribute_id": 12, "display": "text", "sort_order": 0 } ] }
# 4) Sets (replace-set): values = attribute_id → option value
# is_active may be left out: a set without it is on (since 2026-10-28, as in the import);
# "is_active": false switches one off
PUT /products/900/variants
{ "items": [
{ "values": { "12": "s" }, "price": 2400, "sku": "TERRA-TSHIRT-S", "is_active": true },
{ "values": { "12": "m" }, "price": 2400, "sku": "TERRA-TSHIRT-M", "is_active": true },
{ "values": { "12": "l" }, "price": 2600, "sku": "TERRA-TSHIRT-L", "is_active": true } ] }
# 4b) galleries and set binding (optional)
# A gallery is a standalone resource: create it first, then reference it.
POST /galleries
{ "item": { "name": "Синие",
"items": [ { "file": { "id": "<file_id_blue_1>" } },
{ "file": { "id": "<file_id_blue_2>" } } ] } }
# → result.id = "31" (gallery id is a STRING: int64 arrives as a string in JSON)
POST /galleries
{ "item": { "name": "Чёрные", "items": [ { "file": { "id": "<file_id_black_1>" } } ] } }
# → result.id = "32"
# product galleries are REFERENCES — the full set, in the desired order
PUT /products/900
{ "item": { "gallery_ids": ["31", "32"], "gallery_ids_replace": true } }
PUT /products/900/variants
{ "items": [
{ "values": { "12": "s" }, "price": 2400, "sku": "TERRA-TSHIRT-S",
"gallery_id": "31", "is_active": true },
{ "values": { "12": "m" }, "price": 2400, "sku": "TERRA-TSHIRT-M", "is_active": true },
{ "values": { "12": "l" }, "price": 2600, "sku": "TERRA-TSHIRT-L", "is_active": true } ] }
# → variants_info.variants[].gallery_id in the GET /products/900 response confirms the binding
# 5) Verify and publish
GET /products/900/variants
PUT /products/900 { "item": { "is_published": true } }подводные камни:
variant-axesиvariantsесть replace-набор: Отправьте полный комплект; все Недостающее удаляется.- Ось
displayболее узкий:""/text/icon/swatch. The valueselectявляется действительным для атрибута, но не для product ось. - Набор's
priceнеобязательно: пустой product's основание price используется. - Набор's
is_active: Незамеченные средства на, здесь и вPOST /products/importодинаково (с 2026-10-28); before, Набор, написанный здесь без сохранения, переключен off).falseпереключать его off. - Вариант без
labelдает пустую кнопку переключателя; характеристика'sunitне добавляется к нему. Типы, этикетки, фильтры и шаблоны characteristics —GET /docs/characteristics. - Дубликат value комбинация отклоняется — сервер вычисляет заданную подпись.
- Максимально: 20 осей, 500 множеств на product; до 10000 values (
options) По характеристике — 10001-й с отказом400(с 2026 по 10-29; before, 200. Выше 200. options, В ОСНОВЕ ОСТИ ХАРОПАНИЯ перечислены только values тот product's наборы для использования. gallery_idsвPUT /products/{id}это набор ссылок следующийcategories_replaceшаблон: непустая матрица → полная замена в order Пустая или незаполненная; field Опущенный → Обязательные нетронутыми остаются (безопасный копироватьGETТело вступает вPUT); пустой массив +"gallery_ids_replace": true→ Галерея содержимое редактируется через их own конечная точкаPUT /galleries/{id}, не через product.- Набор's
gallery_idссылки Живая галерея любой shop, не обязательно связан с этим product. Вот как ты "взяла галерею от другой product". Еще один арендатор's или несуществующий id →404 GALLERY_NOT_FOUND. Если галерея будет удалена позже, набор не сломается: на читайтеgallery_idвозврат"0"И витрина показывает product's Первая галерея. - Одна галерея может сидеть на нескольких продуктах, а category И статья в The в то же время —
GET /galleries/{id}/usageПоказать полный список. - Набор изображения (
image_id, Шаг 4) и галерея сетов (gallery_id) есть независимый поля:image_idОстается чип и тележка-линия preview,gallery_idУправляет только слайдером в магазине.
6. Сценарий В - отдельно products связанный между собой группировкой
Когда: пластина в 3 цветах × 3 sizes, Каждый из них со своим own фотографии и URL.
# 1) Two axis attributes
POST /attributes
{ "item": { "code": "color", "name": "Цвет", "data_type": "select",
"widget": "swatch",
"options": [ { "value": "light", "label": "Светлый", "color_hex": "#E8DCC8" },
{ "value": "brown", "label": "Коричневый","color_hex": "#8B5A3C" },
{ "value": "black", "label": "Чёрный", "color_hex": "#2B2B2B" } ] } }
POST /attributes
{ "item": { "code": "diameter", "name": "Диаметр", "data_type": "select",
"widget": "select", "unit": "см",
"options": [ { "value": "20", "label": "20 см" }, { "value": "26", "label": "26 см" },
{ "value": "32", "label": "32 см" } ] } }
# label is what the switcher button shows: without it the button is EMPTY, and unit is not added to buttons
# 2) Nine products — regular POST /products, each with its own slug, photos, price
# (or one POST /products/batch, see §8)
# 3) Each product gets values on both axes (replace-set)
PUT /products/808/attributes
{ "items": [ { "attribute_id": 13, "value": "light" },
{ "attribute_id": 14, "value": "20" } ] }
# 4) Group
POST /product-groups
{ "item": { "name": "Тарелка TERRA", "group_type": "variant_group" } }
# → result.id = 5
# 5) Group axes (replace-set) — order of switchers on the storefront
PUT /product-groups/5/axes
{ "items": [ { "attribute_id": 13, "display": "swatch", "sort_order": 0 },
{ "attribute_id": 14, "display": "text", "sort_order": 1 } ] }
# 6) Members (replace-set)
PUT /product-groups/5/members
{ "items": [ { "product_id": 808, "sort_order": 0 },
{ "product_id": 809, "sort_order": 1 } ] }
# 7) Verify: the card returns the ready link
GET /products/808
# → group_info: axes, values, neighbour slugs, current memberподводные камни:
- ось values есть set на product (
PUT /products/{id}/attributes), не на group член: вmembersтотvaluesfield только для чтения. - Все трое
PUTs заменить-set. Добавить десятую product в group — отправлять Все десять. - иметь один card В каталоге вместо девяти, set
catalog_hidden: "true"На остальных - нет. drop вне группы — переключатель на card все еще leads к ним. group_infoв product Ответ является брат изresultfield, Не вложены в него.variants_info,attribute_sectionsиcategoriesсидеть Там тоже.
7.Продукт. images
Загрузка занимает три steps (или один, если file уже в сети; подробности и Правила выращивания находятся в /docs/webcoding, §3. Сквозной "product + photo" Примером может служить §7.3..
POST /v1/storages/files
{ "section": "content", "file_type": "image", "original_name": "plate.jpg" }
# → result.id = <file_id>, upload.id, upload.url
PUT <upload.url> # bytes, no Authorization
POST /v1/storages/files/<upload.id>/done { }
# file already online — a single request
POST /v1/storages/files/from-url
{ "source_url": "https://…/plate.jpg", "section": "content", "file_type": "image" }
# the gallery is created SEPARATELY and once
POST /galleries
{ "item": { "name": "Основная",
"items": [ { "file": { "id": "<file_id_2>" } },
{ "file": { "id": "<file_id_3>" } } ] } }
# → result.id = "31"
# binding on CREATE — preview as an object, galleries as references
POST /products
{ "item": { "name": "Тарелка", "preview": { "id": "<file_id>" },
"gallery_ids": ["31"] } }
# binding on UPDATE — main image as an id string
PUT /products/808
{ "item": { "preview_id": "<file_id>",
"gallery_ids": ["31"], "gallery_ids_replace": true } }подводные камни:
- Создавать и обновлять принимать main image по-разному: в создании —
preview: { "id": … }, Обновление —preview_id: "…"как струна. галереи В обоих случаях используютgallery_ids, массив из id Строки. Обновлениеpreview: {id}также принимается как псевдоним; явноеpreview_idпобеда Всегда перечитывайте product after писать. - Чтобы удалить main image Обновление —
preview_id: ""(пустая строка). - `upload.id` идти
/done, в то время как `result.id` Прикреплен к нему product. Они отличаются друг от друга. values. file_typeэто category (image | video | audio | model | file), не MIME type.- Один
file_idможет быть использован в нескольких galleries и products — Не загружайте то же самое file снова. public_pathВ качестве реакции на хранение используется full объектное хранение URL. На витрине используйте родственника витрины path с обрезкой (/w/{width}/webp{path}), не это URL И не оригинальное.gallery_idsявляется заменой-set Ссылки: Отправить full Список в The желанный order.
7.1 Галерея является отдельной галереей resource
Галерея не имеет live внутри product. Это отдельный shop субъектом с его own CRUD; products, categories (любой type) Только статьи ссылка это.
| Конечная точка | Что он делает |
|---|---|
GET /galleries | тот shop's live galleries с их стороны items, новый first; стриженный — ?page.number=&page.limit= (1.100, без параметров first 50; ответ имеет total и currentPage рядом с result[] |
GET /galleries/{id} | Одна галерея с ее items |
POST /galleries | Создать галерею вместе с items |
PUT /galleries/{id} | обновление: name and/or items |
DELETE /galleries/{id} | мягкий удаление; галерея в использовании cannot быть deleted |
GET /galleries/{id}/usage | где используется: products, categories, статьи и variant sets |
Форма галереи:
{ "id": "31", "name": "Синие", "source": "images", "canvas_id": "0",
"items": [
{ "item_key": "8231acd9-…", "kind": "image",
"file": { "id": "<file_id>", "url": "…" }, "poster": null,
"html": "", "caption": "вид спереди" },
{ "item_key": "4fba917d-…", "kind": "html", "file": null,
"html": "<b>Схема сборки</b>", "caption": "" } ] }Что важно для items:
- тот role (`kind`) это set По данным сервера, Не от вас, а от того, что вы file type:
image | video | audio. Только"html"это set Ручно — у него нет file, только разметка.kindЭто не соответствует file type (e.g."video"на image) →400 GALLERY_ITEM_KIND_MISMATCH. Нет никакого молчаливого фиксирования: молчаливо заменить role Создает витрину, которая не look как что вы посылали; - не-html item требует а file (
400 GALLERY_ITEM_FILE_REQUIRED); ан html item Требуется не-emptyhtml(400 GALLERY_ITEM_HTML_REQUIRED) в большинство 64 KB (400 GALLERY_ITEM_HTML_TOO_LONG); posterЭто видео poster или аудио cover, то же самое{ "id": … };item_keyявляется стабильным item key. Пусто на входе → сервер назначает uuid; твой own Он держится, он держит item "«То же самое» при переупорядочении, так что когда повторная обработка запроса after Тайм-аут, отправьте свой own ключи;itemsвPUT /galleries/{id}это заменить-set: не-empty Список заменят все items полностью; а empty Список (или недостающий) field) означает "не прикасаться". То ясный Галерея — это empty список плюс"items_replace": true: без Флаг последний item cannot Снимаем с себя все. name редактируется отдельно и независимо:{ "item": { "name": "…" } }Не трогать тот items.
Привязка к объектам одинакова для products, categories и статьи:
PUT /products/808 { "item": { "gallery_ids": ["31","32"], "gallery_ids_replace": true } }
PUT /categories/85 { "item": { "gallery_ids": ["31"], "gallery_ids_replace": true } }
PUT /articles/12 { "item": { "gallery_ids": ["31"], "gallery_ids_replace": true } }Над card читать оба fields прибыть: gallery_ids — заказанный set из ссылки, galleries — их содержание. Одна галерея законно сидит на Несколько объектов — Редактирование его содержимого меняет то, как все они look, и это ожидается.
⚠️ galleries может быть дольше чем gallery_ids. Если variant set ссылки Галерея, которая не привязана к product сама по себе, ее содержание все еще в тот card — В конце концов galleries, но не в gallery_ids. Это Преднамеренное: путем отправки GET body обратно в PUT Вы не будете связывать кого-то else's Галерея в сторону product. Отсюда rule: читать set Обязательные от gallery_ids, и look поднимать display Содержание в galleries через id, не position. The preview fallback вычисляется только из BOUND galleries — а product Единственная галерея, которая проходит через set справочные данные preview: null и preview_auto: false. проверенный live.
Галерея в использовании cannot быть deleted: 400 GALLERY_IN_USE: used in N places. Сначала удалите ссылки (на объекты) — gallery_ids: [] + gallery_ids_replace, на sets — gallery_id: "0"), проверять GET /galleries/{id}/usage, и только затем удалять.
пределы: ≤24 items за галерею, name 1.64 Персонажи, ≤15 galleries на объект.
7.2 Что такое молчание ignored — Как проверить, что письмо было effect
Сервер возвращается 200 В таких случаях тоже, но делает что-то другое, чем вы. ожидаемый:
| Что ты послал | Что на самом деле произошло |
|---|---|
gallery_ids: [] без gallery_ids_replace | Читать как «Не трогай», «Не связывай все»" |
categories: [] без categories_replace | "Не трогай". Непустый список заменяет set (§2.3) |
price.currency | Пустота — Пустота shop'используется валюта; любая другая value чем shop's является 400 CURRENCY_IS_STORE_LEVEL |
company_id в запросе body | уронили; key определяет shop |
order Когда создается category | Секция откладывается; последняя |
items на галерее, управляемой документом холста (canvas_id ≠ 0) | Сброшенный; сохраненный items оставаться резервной копией до необязательного — включая запрос с canvas_id: 0 и items В общем, непринужденные работы, items не |
items: [] В галерее без items_replace | читать как «не трогать»; для очистки требуется флаг |
читать gallery_ids / galleries из список | GET /products У нас таких полей нет вообще., GET /categories возвращает их пустыми — списки не возвращаются galleries, только preview |
Проверка after Каждая запись одинакова: перечитывайте объект и compare тот fields Ты послал. А. 200 Ответ доказывает только то, что запрос был разобран..
# wrote
PUT /products/808 { "item": { "gallery_ids": ["31"], "gallery_ids_replace": true } }
# re-read and compared
GET /products/808 # result.gallery_ids == ["31"], result.galleries[0].id == "31"
GET /galleries/31 # items — the ones sent, in the same order
GET /galleries/31/usage # the list contains product 808Три fields Особенно легко неправильно понять:
preview_auto: true— тот preview Показано как a fallback: тот product иметь none его own, Сервер взял на себя first image item из first Галерея, не пишите это preview обратно вpreview_id— Вы получите A дублировать;- а set's
gallery_idравные"0"— Нет никаких ссылок, или галерея была deleted; Витрина показывает product's first галерея; source: "canvas"В галерее — это items Управляется холстом document (canvas_id), и items Вы посылаете не получить там;galleriesболее длительный, чемgallery_ids— В конце концов, они galleries ссылаясь на variant sets но не привязан к product.
7.3.Первый product с а photo — сквозной пример
Этот пример был перенесен с быстрого запуска, который сохраняет только безопасные показания. Заполните §1 и согласуйте письмо с owner. Тебе нужен Баш, curl, jq, права создавать products/galleries и загружать files, а JPEG product.jpg, и существующий shop category в CATEGORY_ID переменный. VIZEN_TOKEN иметь уже переданы в процесс надежно в соответствии с Руководство по аутентификации; отслеживание снарядов и header лесозаготовка есть off. И снова бережет, создает new Объекты — это пример для одного согласованный суд, а не идемпотент import.
set -euo pipefail
: "${VIZEN_TOKEN:?Supply the key securely first}"
: "${CATEGORY_ID:?Choose an existing shop category}"
API=https://api.vizen.shop
# 1. Create an unpublished product. The currency comes from the shop settings (§2.1).
PID=$(curl --fail-with-body -sS -X POST "$API/products" \
-H "Authorization: Bearer $VIZEN_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --argjson category "$CATEGORY_ID" \
'{item:{name:"Sample product",price:{price:100},category_id:$category,is_published:false}}')" \
| jq -er '.result.id | select(. != null)')
# 2. Get an upload link: result.id and upload.id are different identifiers.
UPLOAD=$(curl --fail-with-body -sS -X POST "$API/v1/storages/files" \
-H "Authorization: Bearer $VIZEN_TOKEN" -H 'Content-Type: application/json' \
-d '{"section":"content","file_type":"image","original_name":"product.jpg"}')
FILE_ID=$(jq -er '.result.id' <<< "$UPLOAD")
UPLOAD_ID=$(jq -er '.upload.id' <<< "$UPLOAD")
UPLOAD_URL=$(jq -er '.upload.url' <<< "$UPLOAD")
# 3. Upload the raw bytes without the authorization header, then confirm upload.id.
curl --fail-with-body -sS -X PUT "$UPLOAD_URL" \
-H 'Content-Type: image/jpeg' --data-binary @product.jpg
curl --fail-with-body -sS -X POST "$API/v1/storages/files/$UPLOAD_ID/done" \
-H "Authorization: Bearer $VIZEN_TOKEN"
# 4. Read the final metadata: conversion may change public_path.
curl --fail-with-body -sS "$API/v1/storages/files/$FILE_ID" \
-H "Authorization: Bearer $VIZEN_TOKEN"
# 5. Create a gallery and bind it to the product; a separate preview is not needed.
GALLERY_ID=$(curl --fail-with-body -sS -X POST "$API/galleries" \
-H "Authorization: Bearer $VIZEN_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --arg file "$FILE_ID" \
'{item:{name:"Sample gallery",items:[{file:{id:$file}}]}}')" \
| jq -er '.result.id')
curl --fail-with-body -sS -X PUT "$API/products/$PID" \
-H "Authorization: Bearer $VIZEN_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --arg gallery "$GALLERY_ID" \
'{item:{gallery_ids:[$gallery],gallery_ids_replace:true}}')"
# 6. Verify the result by reading; the product is still unpublished.
curl --fail-with-body -sS "$API/products/$PID" \
-H "Authorization: Bearer $VIZEN_TOKEN"Сравните name, price, category, is_published:false и связанная галерея с запросом, который вы отправили; GET /galleries/{id} должен содержать загруженный file. Галерея's first photo служит в качестве product preview. В content sections тот оригинал может быть преобразован в WebP; Используйте финальный public_path after /done, и хранить ссылки на стабильные file_id. Для file в public URL, заменить steps 2-4 с одним from-url § 7; не требуется подтверждение через /done. Для всех других операций галереи используйте § 7.1-7.2 без секунды. set После проверки, передайте мне все, что я могу. result в owner; Этот пример Не публикует ничего.
7.4.Новый pictures существующий products: replace тот bytes, keep каждый link
Чтобы поставить new Картина, где старый, replace тот file's bytes. The file_id Остается прежним, поэтому галерея (gallery_id, каждый item_key, order, caption), preview_id, variant sets, cards и сцены keep Указывая на то же самое file и показать new Ничего на фотографии. product Написано: Нет PUT /products, нет PUT /galleries. Имя, price, categories, SKU и Публикация остается такой, какая она есть. storage:write.
# 1. Read the file and keep what you will compare: public_path (and the old bytes, for a rollback)
GET /v1/storages/files/<file_id>
# 2. Ask for an upload link for the SAME file
POST /v1/storages/files/<file_id> { "original_name": "front.png" }
# → result.id = <file_id> (unchanged), upload.id = <file_id>, upload.url
# 3. Bytes without Authorization, then confirm with upload.id
PUT <upload.url> # Content-Type: image/png
POST /v1/storages/files/<file_id>/done { }
# 4. Verify: same id, new name, new public_path
GET /v1/storages/files/<file_id>Правила:
- The new bytes Показать везде file используется. Один file Можно сидеть несколько galleries и products (§7) Перед массовым бегом постройте карту
file_id → usesизGET /galleries(all pages) и products'preview_id. Если разделяемый file должны быть разными pictures для разных products, загружать new file 7 и внесите в галерею сPUT /galleries/{id}: тот fullitemsСписок, каждыйitem_keyотправленный обратно без изменений (§7.1)). - Заканчивайте каждый file сразу. Правильно. after тот replace тот file уже сейчас указывает в new, все еще empty объект, так что до тех пор, пока
PUTиdoneуспех Фотография может отсутствовать на site. А. failedPUT→ повторять steps 2-3 для это file. - Проверь. bytes before тот replace.
doneОтказаться от одного empty загружать (400 EMPTY_FILE) или картинка над image limit (400 FILE_TOO_LARGE, 10 MiB через default), и отказ удаляет file: galleries и preview Не надо, не надо, не надо.-empty files внутри limit. - PNG и JPEG становиться WebP в
done(quality 90, прозрачность сохраняется), когда Это меньше:public_pathи изменением протяженности, то естьfile_idделать Нет, магазин. links черезfile_id, never через URL. - На сервере нет никаких отмен. Старый bytes не сохраняется как version Ты можешь восстановить., download тот file из
public_pathbefore тот replace и keep с его помощьюfile_id. Откат - это то же самое steps с старый bytes. - Конфликты и возобновление. The replace Не имеет «ожидаемого старого» version" field. Прочти file просто before шаг 2 и compare
public_pathс помощью value в Разное означает, что кто-то изменил список. file, Так что пропустите row. Держи. журналfile_id → done. На повторе, пропустить закончил rows: повторяющийся replace Безвредно, но стоит два more звонки. - Отказы: а draft key на live file →
400 FILE_CONTOUR_MISMATCH(использовать live key); другой shop's file или unknown id →404 NOT_FOUND; а file из одного site-folder освобождение →FILE_IN_RELEASE(publish а new вместо освобождения);409 FILE_CHANGED_RETRY→ тот file В тот же момент он изменился, прочитайте его снова.. - Скорость. The replace и
doneделиться shop's file бюджет 180 Позвонить минутку (all Ключи и люди из shop вместе, так ~4 000 files Это займет 45-60 минут.Читать далее (GET) использовать бюджет отдельного чтения. Над429, ждатьRetry-After.
8. Навал import
POST /products/batch
{ "items": [ { … }, { … } ] }Ответом является a частичный успех: каждый item получает own result или error. Проанализируйте ответ item через item; в целом 200 Не значит, что все Успешно. results[] матч index к оригиналу position: успешный item содержит id, а failed содержит error. Возвращать только failed items Чтобы не дублировать products которые уже были приняты.
Безопасно import order:
- Ключевой паспорт (§1), проверка currency и contour, owner подтверждение.
- Категория:Настройка order через
/categories/move. - атрибуты и options → записывать их
ids; Они нужны везде after. - Файлы → Построить
local name → file_idкарта. - Галереи (
POST /galleries) → строитьphoto set → gallery_idкарта. Галерея является created before тот product: тот product ссылаться на него, Не в другую сторону round. - Одна канарейка product,
is_published: false→ Прочитайте его назад → compare каждый field Вы послали показать owner. - Остальная часть каталога в пакетах.
- Ссылки (variants или групп).
- Публикация:
is_published: true. - Проверка на витрине: category page и product card return
200и Содержит то, что ожидается.
Императивность. Сервер не сохраняет ваш external product key. Держи. местный manifest external SKU → product id → gallery_id → file_id → slug и Проверить существование before создавать: GET /products/by-slug/{slug}. В противном случае Rerun будет создавать дубликаты.
откат. Не удалять - не публиковать: is_published: false. Это Обратимая, но product'адрес перестает отвечать (404, или постоянный 308) в его раздел — §12.3); catalog_hidden: "true" В одиночку сохраните адрес и Вынимает карту только из сетки.
8.1 Весь каталог — POST /products/import
POST /products/batch Только магазины cards, 100 за раз, и каждый повтор создает new products. Для каталога, который регулярно перезагружается, есть второй конечная точка:
POST /products/import
{ "items": [ {
"sku": "ART-001", # KEY: the row finds its product by it
"name": "Лампа настольная",
"slug": "lampa-nastolnaya", # empty on a new product → generated from the name
"description": "…",
"base_price": 4900, "old_price": 6900, # integers, in the SHOP currency
"category_id": 12, # or "category_slug": "svet"
"status": "new", "is_published": true,
"tags": ["распродажа"],
"attributes": [ # attribute CODES, not ids
{ "code": "height", "value": 42 },
{ "code": "color", "value": "red" },
{ "code": "tags_multi", "value": ["a", "b"] }
],
"variant_axes": [ { "code": "color", "display": "swatch" } ],
"variants": [
{ "values": { "color": "red" }, "sku": "ART-001-R", "price": 4900 },
{ "values": { "color": "blue" }, "sku": "ART-001-B" }
],
"images": ["<file_id>", "<file_id>"] # array order = gallery order
} ] }Чем отличается от `/products/batch` (конечная точка остается; она не заменяется):
/products/batch | /products/import | |
|---|---|---|
| Rows в запросе | 100 | 5,000 |
| Что за row держать | card | card + attributes + топоры и sets + image order |
| Повторять | Создает дубликаты | Обновления от `sku` |
| Адрес продукта | Ваш местный manifest SKU → id | тот sku само собой |
Императивность. sku это required Уникальный в пределах shop. А. row Найдет он свой product с помощью него: none — Один из них created (created); существует — это updated (updated). Местный manifest для повторных загрузок больше не требуется.
Пустота = нетронутая. скалярный field отсутствующий в row остается неизменным на существующий product. Списки (attributes, variants, images) заменить-set: а не-empty Список полностью заменяет set, ан empty Оставляющий его нетронутым, empty Вместе с одним из attributes_replace / variants_replace / images_replace Поле не в контракте, не в договоре. (SEO, preview, сцена, Группировки, запасы) являются NEVER тронутый тем, import — Редактировать их через свои own конечные точки.
Ответом является per row. HTTP 200; каждый row's Результат находится в results[i]:
{ "rows": 3, "created": 1, "updated": 1, "skipped": 1,
"results": [
{ "row": 1, "product_id": "5001", "action": "created", "errors": [] },
{ "row": 2, "product_id": "4812", "action": "updated", "errors": [] },
{ "row": 3, "product_id": "0", "action": "skipped",
"errors": [ { "code": "CATEGORY_NOT_FOUND", "field": "category_id",
"message": "категории 99 нет в этом магазине" } ] }
] }row Это ROW number, считать от одного (items[0] → row: 1); тот order из results матчи items. action: "skipped" средство ничего из этого row Поступил в базу данных — нет product, нет attributes, нет sets: партия пишется в одной сделке, и не может быть "половины а" product" в ней.
Коды Row для отказа: SKU_REQUIRED, DUPLICATE_SKU_IN_BATCH (BOTH rows есть Отвергнутый — только file's author Знать, кто из них прав), PRODUCT_NAME_REQUIRED и CATEGORY_REQUIRED (new products только), CATEGORY_NOT_FOUND, CATEGORY_TYPE_MISMATCH, OLD_PRICE_LESS_THAN_PRICE, SLUG_TAKEN, ATTRIBUTE_NOT_FOUND, ATTRIBUTE_VALUE_INVALID, DUPLICATE_ATTRIBUTE_IN_ROW, NO_VARIANT_AXES, VARIANT_AXIS_NOT_SELECT, VARIANT_VALUES_MUST_COVER_AXES, VARIANT_VALUE_UNKNOWN_OPTION, DUPLICATE_VARIANT_COMBO, DUPLICATE_VARIANT_SKU, AXIS_ALREADY_GROUP_AXIS (Атрибут уже является групповой осью product), IMAGE_NOT_FOUND, GALLERY_ITEM_KIND_MISMATCH, GALLERIES_TOO_MANY (тот product Уже есть 15 galleries — тот import Не имеет места для своего own), TOO_MANY_* и ROW_INVALID.
ROW_INVALID — тот row нарушение условий договора: отрицательное product или set price, а field выше длинных кеп, display вне словарного запаса text · icon · swatch. field несёт path в field (base_price, variants[0].price), message тот reason. Ограничения строк проверяются как целые, включая гнездовые attributes, топоры и sets: плохой row отвергается в его own и не сбивает своих соседей.
OLD_PRICE_LESS_THAN_PRICE Сравнение цен AFTER слияние с product's current values. А. price Список, который отправляет только base_price выше хранимых old_price получает row Отказ - отправьте обе цены вместе.
Только просьба недействительна AS А. WHOLE получает HTTP error:
| HTTP | Код | Когда |
|---|---|---|
400 | валидатор message | empty items или more более 5000 rows |
400 | IMPORT_TOO_MANY_ATTRIBUTES / IMPORT_TOO_MANY_VARIANTS / IMPORT_TOO_MANY_IMAGES | total пакетный колпачок (1,200,000 / 200 000 / 200 000)) |
401 / 403 | AUTH_*, PAT_SCOPE_MISSING | Нет, нет, нет. shop, нет catalog:write правильно |
403 | PAT_CONTOUR_MISMATCH | dev key: объемный import Пишет только для live shop, и key's contour Уменьшает запрос off before обработчик |
413 | REQUEST_TOO_LARGE | body больше 64 MiB (тот gRPC side принимает тот же) |
429 | IMPORT_RATE_LIMITED | минута ROW бюджет превышен; message Как долго ждать |
429 | PRODUCT_LIMIT_REACHED | план's product КОБРА: подсчитывает партию's NEW rows; Если места недостаточно, none написанный |
тело size. Запрос на кэп составляет 64 MiB, и 5000 rows не always стойка: a row со 100+ attributes весит около 10 KB, Таких 5 тысяч человек rows подходы тот limit. Рекомендация: 100+ attributes за product отправлять нет more чем 1,000 rows по запросу (keep 5,000-row партии для price Список с десятком fields). Превышение его дает явное 413 REQUEST_TOO_LARGE, Не уронить Связь: когда вы видите ее, разделите file Вместо того, чтобы повторять Тот же запрос.
Изображения. images брать file_ids из ALREADY загруженный images (§5; не существует загружать URL Вот, колпачок. 24 кадра за row: Что такое обычный Галерея принимает (§7), поэтому import Не собирайте ничего, что standard editor Позже он отказался от спасения..
Все в одном row's кадры входить в ONE галерея product — его own: created на first import, повторно используется на более поздних; вторая галерея не появляется. own" средство created от import Нигде не используется else — не привязанный к другой product, category или article, не упоминаются в а variant set, включая Если такое связывание существует только в dev draft. Все else иностранный в import: ручная галерея, галерея, расположенная на нескольких cards сразу (тот standard model — "Выбрать галерею из другой product"), холст Галерея. import не изменяет иностранную галерею, создает ее own Если бы это было product Уже есть 15 galleries (Для каждого объекта, row получать GALLERIES_TOO_MANY.
Галерея order Это твой. The import помещает свои own галерея FIRST в product's связующие (The Bindings) first Галерея является лицом card) Только когда это создает. Ан order ты set вручную через PUT /products/{id} (gallery_ids) Не тронуты перезагрузками: если вы поставите manual галерея first, Он остается first Однако много раз в price Если вам нужен импортный first, reorder Обязательные сами.
Что? import изменения в кадрах. Только set из file_ids и их order. Подписи к кадрам (caption), плакаты, html items и рама role есть Ваш: на раме, которая выживает при загрузке (то же самое) file_id) Они хранятся. В кадре больше нет images это deleted Вместе с его caption — Рамка является просто ушла.
Умеренность. Если product Представляется на общий рынок (is_shared) и уже одобрены, меняя покупательский подход content — name, description, цены, category, теги, attributes, Галерея кадров - удаляет ""Одобренный" и возвращает card В очереди на умеренность. rule То же самое как и регулярные product Изменение обнаруживается путем сравнения before/after, не в силу field Скачать: Reuploading the same file Не трогать статусы.
Что? import не делать. Не удаляет products отсутствующий в file (а skipped product Он остается таким, каким был; он не создает categories и attributes — Создавайте их заранее (§ 2, § 3); они не приносят files через URL.
8.2 Скорость импорта
Над 429 RATE_LIMITED Ждать паузы, данной в Retry-After; Не повторять
- Успешная часть партии. Бюджет запроса распределяется между всеми участниками.
компании, включая другие ключи и staff; числовой limits — /docs/webcoding §10. Записанный загрузчик использует несколько запросов, from-url один; limit Параллельность. 503 честь Retry-After Если он будет возвращен.
9. Ошибки.
The main Форма - это RPC конверт:
{ "error": "rpc error: code = InvalidArgument desc = INVALID_WIDGET" }Машина code Это first слово after desc = . Общие:
| Код | значение |
|---|---|
PAT_METHOD_NOT_ALLOWED | Метод недоступен для ключей этого type вообще |
PAT_SCOPE_MISSING | Право отсутствует; required Один из них назван в message |
AUTH_COMPANY_PROBLEM | The shop Не определено - проверьте key |
INVALID_WIDGET | Виджет снаружи text · select · icon · swatch · photo |
INVALID_DATA_TYPE | Тип снаружи string · number · bool · select · multiselect · date · color · url · group |
INVALID_CODE, INVALID_OPTION_VALUE | Атрибут code и вариант value Латинские слизни, не читаемые человеком text |
FILE_IN_USE | The file cannot быть deleted: он связан |
CATEGORY_FILE_NOT_FOUND (404) | А. category's preview_id или seo.og_image_id не является а live file твоей shop. Чек прибыл с выпуском «Галереи»: такое письмо раньше проходило бесшумно |
URL_NOT_ALLOWED, URL_FETCH_FAILED, FILE_TOO_LARGE | Загрузить URL |
Галереи (§7) отвечают own коды:
| Код | HTTP | значение |
|---|---|---|
GALLERY_NOT_FOUND | 404 | Нет такой галереи — либо она принадлежит другому арендатору, либо она была deleted. Один code в обоих случаях: сервер не подтверждает, что другой арендатор's resource существует |
GALLERY_IN_USE: used in N places | 400 | Галерея используется; удалите ссылки, GET /galleries/{id}/usage показывает, где |
GALLERY_NAME_REQUIRED / GALLERY_NAME_TOO_LONG | 400 | Имя есть required, максимум 64 символа |
GALLERY_TOO_MANY_ITEMS | 400 | Более 24 items в галерее |
GALLERY_DUPLICATE_ITEM_KEY | 400 | Тот же самый item_key появляется дважды |
GALLERY_ITEM_KIND_MISMATCH | 400 | The role Отправленное не соответствует file type (или files из этого category не показаны в galleries) |
GALLERY_ITEM_FILE_REQUIRED | 400 | Ан item без kind: "html" не имеет file |
GALLERY_ITEM_HTML_REQUIRED | 400 | А. kind: "html" item иметь empty разметка |
GALLERY_ITEM_HTML_TOO_LONG | 400 | Разметка по пунктам превышает 64 KB |
GALLERY_FILE_NOT_FOUND | 404 | file_id или poster.id не является а live file твоей shop |
GALLERIES_TOO_MANY | 400 | Более 15 galleries на объект |
GALLERY_DUPLICATE_LINK | 400 | Одна и та же галерея дважды в списке gallery_ids |
GALLERY_MANAGED_BY_CANVAS | 400 | Ты cannot Позволяет холст mode и посылать items В одном запросе: свяжитесь first, затем items |
GALLERY_DUPLICATE_CANVAS | 400 | Это полотно document Управляет еще одной галереей shop |
CANVAS_DOCUMENT_NOT_FOUND | 404 | canvas_id не является а live document твоей shop |
CANVAS_TYPE_MISMATCH | 400 | The document существует, но является неправильным type |
⚠️ Более 15 values в gallery_ids Отвергаются одним-item конечная точка before машина code — с валидатором message (value must contain no more than 15 item(s)). голый GALLERIES_TOO_MANY code исходит из POST /products/batch, где ошибки возвращаются в item.
Есть ли у тебя второй Форма — для одного unknown path. Оно приходит вместе с 404 и содержит намек:
{ "error": "not_found", "path": "/v1/products/808",
"hint": "catalog is unprefixed (/products); storage/account/org under /v1",
"docs": "/openapi.json" }Клиент должен уметь разбирать и то, и другое. Отличительный признак: наличие тот path field.
The load Ограничитель отвечает 429 и указывает время ожидания — уважайте его и повторное рассмотрение просьбы after пауза.
10. Условия остановки.
Остановитесь и спросите owner если:
- тот shop currency не соответствует price список currency;
- тот key пишет в live shop И не было подтверждения для объемного письма;
- after Творение (Создание) product не найдено в его category filter;
- а value Отличается от отправленного, и это не описано здесь;
- а public page Ответить на что-то другое, чем
200; - а
429Прибывает и возвращается after Пауза не помогает.
И не подлежащий обсуждению rule: тот key never заканчивается в любом file, вести, HTML, отчет или message. Он находится в отдельном магазине с 600 разрешения.
11. Ссылка: fields С сюрпризами
| Поле | Тип | Что важно |
|---|---|---|
price.price | целое число | В этом shop Валюта. Никакой дробной части |
price.currency | струна | Пустота на письме = shop Валюта – другая валюта 400 CURRENCY_IS_STORE_LEVEL. Ответ несет в себе shop валюта |
category_id | целое число | первичный category |
categories[] | множество целых чисел | Дополнительные. Обновление непустого списка заменять тот set; Потребности в очищении [] + categories_replace: true |
preview / preview_id | объект / строка | создавать — preview: {id}; обновление — preview_id: "…" (preview: {id} Там есть псевдоним; preview_id: "" удаляет image) |
catalog_hidden | струна | "" / "true" / "false" — не булевой |
is_published | булевый | Обычный флаг |
order (category) | целое число | Игнорируемые на создание — Раздел будет последним. order через /categories/move |
widget (атрибут) | струна | text · select · icon · swatch · photo |
display (ось) | струна | "" · text · icon · swatch — более узкое, чем widget |
data_type (атрибут) | струна | Ось переключателя всегда select |
values (set) | объект | attribute_id (как струна опция value |
gallery_ids | массив струны | Галерея Ссылки (int64 непустая замена; пустая без gallery_ids_replace → "Не трогать" |
galleries | массив объектов | Только на карточке прочти. Пусто в списках. Может быть длиннее, чем на карточке. gallery_ids: В конце — galleries ссылочные наборы |
items_replace (галерея) | булевый | Нужно очистить items: пустой items Без флага = "не трогать"" |
gallery_id (set) | струна | Любые живые галереи shop, не только "своего" own". "0" = Никаких ссылок или галереи не было удалено. |
kind (галерея item) | струна | установленный сервер от file type. Ручно — только "html". Несоответствие = отказ |
item_key (галерея item) | струна | стабильный key. Пустой - сервер присваивает один; ваш own в повторном порядке |
source, canvas_id (галерея) | струна | "canvas" = items Управляется документом Canvas; items Отправлено игнорируется |
preview_auto | булевый | true = preview Заполняет запасной вариант из галереи. preview_id |
public_path (file) | струна | Полное хранилище URL. На витрине — родственник path с обрезкой |
page.number | целое число | Начало 1.Необходимо, если page.limit Проходит |
group_info, variants_info, attribute_sections, categories | объекты | Братья и сестры result в product Ответ, а не его поле |
12.Изменение того, что уже существует
Измеряется на стенде 2026-10-28.
12.1. PUT /products/{id} Меняйте только то, что вы отправляете
отсутствующий field Сохраняет свои value — is_published, catalog_hidden, name, category_id Отправляй поля, которые ты меняешь, и ничего больше. Эти поля: вот где небольшое исправление теряет данные.
| Ты посылаешь | Что происходит |
|---|---|
price: {price: 900} без old_price | Прорыв через price становится 0: price Отправь обоих или уйди. price выходить. Никогда не возвращайте `price` Ты читала в то время как price.promotion_name установлен или price.price отличающиеся от price.catalog_price: Чтение показывает, price after поощрения и price Правила, и написание его делает скидку постоянной. price это price.catalog_price |
seo с одним field | пустой text поля (slug, Заголовки, описание, ключевые слова) сохранены, но og_image_id, noindex и nofollow Переписывается — а seo Без них они будут устранены. image и оба флага. Отправьте все три с каждым seo |
categories: [X], tags: [X] | заменить Весь список с [X] (§2.3); [] Ничего не меняет |
description: "", sku: "", preview_id: "" | ясно, что field. name: "" это 400 |
stock_quantity | Недооцененный; запас PUT /products/{id}/stock, Закрытые ключи (/docs/stock) |
Атрибутов в этом нет body (неизвестный field это 400 INVALID_REQUEST): PUT /products/{id}/attributes Заменять собой product'весь set из values.
12.2 Один field на многих products
- Снимок. Читать каждый product Вы будете трогать и держать JSON — Это Ваш откат. Продолжайте.
price.catalog_priceкак основание price, неprice.price(§12.1).GET /products?attribute_codes=…Ответы как покупатель: Он оставляет неопубликованным и скрытым products и attributes скрытый от покупатели (/docs/characteristics§5) - читать их на product. - Канарская. Напиши одну product, Перечитывайте, открывайте page.
- Писать. Продукты с одной
sku:POST /products/importс рядами{"sku": …, <the field>}— Отсутствующие скалярии сохраняют свои value, Один запрос на 5 000 строк. Безsku:PUT /products/{id}за product (§12.1). Атрибуты являются заменой в обоих: Чтобы изменить один, отправьте product's полный набор, построенный из снимка, или остальные теряются. - проверять Прочитав все и сравнив с планом.
- откат = То же самое пишут со снимком values (Цены как на шаг 1).
12.3 Возьми product off Продажа и возврат
| Для покупателя | is_published: false | catalog_hidden: "true" |
|---|---|---|
карточка (GET /products/{id}) | 404 | открывать |
| адрес магазина | Не найдено: постоянный 308 в ближайший к нему раздел адреса, когда shop's miss_fallback находится (/docs/redirects), иначе 404 | открывать |
| Сети разделов, поиск, подсчет разделов | уходить | уходить |
| коммутатор групп | уходить | оставаться |
| карта сайта | уходить | оставаться |
| Добавление в корзину | отказываться | разрешенный |
А. product - Уже в тележке, она там и может быть заказана. с is_published: true или catalog_hidden: "". А. 308 является постоянным: а браузер, который последовал за ним, может продолжать переходить в раздел after тот product это назад. catalog_hidden Это пауза в сетках и поиск только — product это Продается по адресу; только is_published: false Прекратить продажу.
12.4 Копии и удаление
- `POST /products/{id}/copy`, body
{}→{"new_id": …}. То же самое shop, и а выталкивать key Только (Dev) key это403 PAT_CONTOUR_MISMATCH). Копия являетсяCopy of <name>, Неопубликованный, с пустымskuи новый slug. Он держится Описание, цены, categories, теги, preview, SEO, Сцена (как новая) копия), attributes, содержание blocks, различные оси и наборы (ихskuочищенный), combo содержание и Ссылки на один и тот же galleries — редактирование такого Галерея меняет оба products. Не копировать:catalog_hidden, Группировка, обзоры, уровни запасов, отношения, мульти-product Содержание (копия являетсяstandard). - `DELETE /products/{id}`, body
{}(Мягкий: ответ несетdeleted_after(+30 дней, но есть Нет восстановления и удаленный product Его адрес 308-е до последнего. category (miss_fallback,/docs/redirects). Заказы Они сохраняют свои линии, оставляя тележки, группы и комбо (и комбо). combo price). - `DELETE /categories/{id}`, body
{}. Отказ, если у него есть подкатегории (CATEGORY_HAS_CHILDREN), products — первичный или дополнительный, неопубликованный (CATEGORY_HAS_PRODUCTS) — или статьи (CATEGORY_HAS_ARTICLES); Домой page этоHOME_CATEGORY_UNDELETABLE. Перемести products Первый (§12.1)).
12.5 Наборы и мультипликаторы-products
- А. set (combo):
PUT /products/{id}/combo-items{"items":[{"component_product_id":6,"quantity":1,"price_mode":"inherit"}]}— заменить-set максимум 20 items. Не пустой список делает product аcombo, Пустой возвращает егоstandard.price_mode:inherit·fixed·percent·freeсprice_value. Не гнездиться (COMBO_IS_COMPONENT,COMPONENT_IS_COMBO), Никаких дубликатов, никаких иностранных или удаленные компоненты (COMPONENT_NOT_FOUND). Читать:GET /products/{id}/combo. - Многократный-product (контейнер):
PUT /products/{id}/kind {"kind":"multi"}, затемPUT /products/{id}/children {"items":[{"product_id":5,"sort_order":1}]}— заменить-set максимум 500standardproducts, Каждый в одном контейнере Только.Возврат кstandardтолько когда содержимое пусто (PRODUCT_HAS_CHILDREN).comboникогда set через/kind. - Не посылать `combo-items` Чтобы многократно-product: не отказано и Он превращает контейнер в set.
12.6 Группы
PUT /product-groups/{id} изменениях, name только; …/members и …/axes есть замещающие наборы (§6)). DELETE /product-groups/{id} с {} удаляет members и оси сразу: products есть free для другой группы и их карточки делают Не меняться иначе.
12.7 Переместить каталог в другой shop
Нет никакого export Без креста-shop Копия. key Работает в одном shop, Так что тебе нужно а key за shop.
- Прочти source: Список, затем каждая карта — список не несет описание, galleries или attributes Скрытые от покупателей.
- Структура в целевой: categories, затем attributes с их стороны options и этикетки, то каждый атрибут покупатель доступ (
PUT /attributes/{id}/access— новый attributes скрытый,/docs/characteristics). - Файлы: а file одного shop не видны другим. воссоздать каждый с его публичного обращения к
POST /v1/storages/files/from-url, или загрузить тот bytes (§7). - Продукты:
POST /products/importрядыsku, с новым category и file Сначала Канарейка. import не носить с собойcatalog_hidden— набор с нимPUT /products/{id}после. - Связи между products — Группировки (§6), множества и многообразия-products (§12.5) — re-created after все products Есть, с новыми ИД.
- проверять цель field через field против source.
неподвижный по key: Уровень запасов (только кабинки), /docs/stock) и взгляд Промоушен. (promotions:*) и price правила (pricing:*) есть created Опять в цель shop, с новым product ids.
13 Где дальше
| Документация | О нас |
|---|---|
/docs/webcoding | Страница layout, HTML blocks, images и обрезка, limits |
/openapi.json | Полный API schema |
/v1/account/token | Ключевой паспорт: contour, shop, currency, права |
/llms.txt | Короткий API Карта для одного AI агент |