Skip to content

Синхронизация каталога и остатков

Идентификаторы: вы передаёте свои коды (external_id) для складов, категорий, видов цен и товаров. В запросах остатков и цен используете те же коды (store_id, product_id, price_id).

Импорт выполняется двумя вызовами: сначала каталог (склады, категории, товары), затем остатки и цены. Данные по умолчанию сливаются по внешним идентификаторам, но при необходимости можно запросить полную замену каталога.

Остатки и цены: по умолчанию дельта — обновляются только переданные пары (склад+товар, товар+вид цен); остальное не трогается. Если в запросе inventory или prices передать full_replace: true, очищаются только реквизиты остатков (таблица остатков) или цен (таблица цен) по клиенту; справочники склады и виды цен не трогаются — они задаются в каталоге. Затем вставляются только данные из запроса. Так можно выгружать из 1С полный срез из ВТ без хранения дельты и без «перемножения нулей» — пришло то, что есть; чего нет в запросе, того нет и в системе после полной замены.

Новые API: inventory и prices

Если вы работаете по новым эндпоинтам POST /api/v1/import/inventory (остатки) и POST /api/v1/import/prices (цены), в импорте каталога обязательно передавайте price_types. Без видов цен в каталоге импорт цен не найдёт вид цен по коду и записи будут пропущены. Для старых клиентов, которые не шлют price_types, ошибки не будет.

Во всех запросах обязательны заголовки X-Client-ID и X-Client-Secret. Content-Type: application/json.


POST /api/v1/import/catalog

Импорт складов, категорий, видов цен и товаров. Виды цен задаются кодом (external_id) и названием; в импорте цен передаётся код товара (product_id) и код вида цен (price_id).

Тело запроса

json
{
  "full_replace": true,
  "stores": [
    {
      "external_id": "WH01",
      "name": "Основной склад",
      "description": "",
      "address": "",
      "contact": "",
      "is_available": true
    }
  ],
  "categories": [
    {
      "external_id": "CAT01",
      "name": "Напитки",
      "parent_id": "",
      "properties": {}
    }
  ],
  "price_types": [
    { "external_id": "base", "name": "Базовая" },
    { "external_id": "yandex_eda", "name": "Яндекс Еда" },
    { "external_id": "promo", "name": "Акция" }
  ],
  "products": [
    {
      "product_id": "ART-001",
      "vendor_code": "ART-001",
      "category_id": "CAT01",
      "product_name": "Товар",
      "description": "Описание",
      "price": 99.99,
      "barcode": {
        "value": "4601234567890",
        "type": "EAN13",
        "weight_encoding": ""
      },
      "measure": {
        "quantum": 1,
        "value": 1,
        "unit": "PCE"
      },
      "is_catch_weight": false,
      "images": ["https://example.com/img.jpg"],
      "properties": { "weight": "200", "brand": "Nike" }
    }
  ]
}
  • full_replace (опционально):
    • trueполная замена каталога: все товары клиента помечаются как Удален, очищаются все остатки и все цены по клиенту, затем создаются/обновляются только переданные в запросе. После такого импорта отправьте актуальные остатки (POST /api/v1/import/inventory) и цены (POST /api/v1/import/prices). Поведение как при полной выгрузке в Commerce ML.
    • false или отсутствие поля — только обновление/создание: существующие товары не помечаются Удален, остатки и цены не очищаются, данные сливаются по product_id.
  • stores: код (external_id) обязателен; в импорте остатков передаётся как store_id.
  • categories: parent_id — пустая строка для корня, иначе код родителя.
  • price_types: массив видов цен: код (external_id) и name. Если не переданы — ошибки нет (обратная совместимость). При работе по новым API (inventory и prices) передавайте price_types обязательно — иначе в импорте цен записи с неизвестным видом цен будут пропущены.
  • products: product_id, category_id, product_name, price — основные поля. images — строка URL, массив строк или массив объектов { "url", "order", "hash" }. Доп. свойства — properties или attributes.

Ответ 200

json
{
  "success": true,
  "message": "Catalog imported successfully",
  "stats": {
    "stores": 1,
    "categories": 1,
    "price_types": 3,
    "products": 1,
    "duration": "1.234s"
  }
}

POST /api/v1/import/stocks (устарел, используйте inventory + prices; работает до 31.08.2026 года)

Импорт остатков и цен по складам и товарам в одном запросе. Склады и товары должны быть ранее импортированы через каталог.

Устаревший эндпоинт

Рекомендуется использовать: POST /api/v1/import/inventory (остатки) и POST /api/v1/import/prices (цены по видам цен). У этого эндпоинта одна цена на товар на маркетплейс; разные цены по складам не поддерживаются. Работает до 31.08.2026 года.

Тело запроса

json
{
  "full_replace": true,
  "stocks": [
    {
      "store_id": "store-1",
      "product_id": "prod-1",
      "stock": 10.5,
      "prices": [
        {
          "marketplace": "yandex_eda",
          "price": 199.99,
          "old_price": 249.99
        },
        {
          "marketplace": "glovo",
          "price": 199.99,
          "old_price": 0
        }
      ]
    }
  ]
}
  • full_replace (опционально): true — очистить все остатки и цены по клиенту, затем вставить только из запроса; иначе дельта.
  • store_id — код склада из каталога.
  • product_id — код товара из каталога.
  • stock — количество (дробное для весовых).
  • prices: массив цен по маркетплейсам. marketplace — код в GoSync (yandex_eda, glovo, wolt20 и т.д.). old_price опционален.

Ответ 200

json
{
  "success": true,
  "message": "Stocks imported successfully",
  "stats": {
    "stocks": 10,
    "prices": 25,
    "duration": "0.5s"
  }
}

POST /api/v1/import/inventory

Импорт остатков по складам и товарам. Обновляется только таблица остатков (product_stocks). Склады и товары должны быть ранее импортированы через каталог. Авторизация: X-Client-ID и X-Client-Secret.

Тело запроса

json
{
  "full_replace": true,
  "stocks": [
    {
      "store_id": "WH01",
      "product_id": "ART-001",
      "stock": 10.5
    }
  ]
}
  • full_replace (опционально):
    • trueполная замена остатков: удаляются только реквизиты остатков (таблица остатков по клиенту); справочник складов не трогается. Затем вставляются только переданные в запросе. Удобно для выгрузки из 1С полного среза из ВТ без хранения дельты.
    • false или отсутствие поля — дельта: обновляются только переданные пары (store_id + product_id); остальное не меняется.
  • store_id — код склада из каталога.
  • product_id — код товара из каталога.
  • stock — количество (дробное для весовых).

Ответ 200

json
{
  "success": true,
  "message": "Stocks imported successfully",
  "stats": {
    "stocks_saved": 10,
    "duration": "0.2s"
  }
}

POST /api/v1/import/prices

Импорт только цен по товарам и видам цен. Обновляет таблицу product_prices. Виды цен обязательно передайте в импорте каталога (price_types с external_id и name) — иначе записи с неизвестным price_id будут пропущены. Аналогия со складами: остатки = товар + склад + значение; цены = товар + вид цен + значение. Признак «акция» настраивается при выгрузке. Авторизация: X-Client-ID и X-Client-Secret.

Тело запроса

json
{
  "full_replace": true,
  "prices": [
    { "product_id": "ART-001", "price_id": "base", "value": 99.99 },
    { "product_id": "ART-001", "price_id": "yandex_eda", "value": 199.99 },
    { "product_id": "ART-001", "price_id": "promo", "value": 149.99 }
  ]
}
  • full_replace (опционально):
    • trueполная замена цен: удаляются только реквизиты цен (таблица цен по клиенту); справочник видов цен не трогается. Затем вставляются только переданные в запросе. Удобно для выгрузки из 1С полного среза без хранения дельты.
    • false или отсутствие поля — дельта: обновляются только переданные пары (product_id + price_id); остальное не меняется.
  • product_id — код товара из каталога.
  • price_id — код вида цен из каталога (price_types[].external_id).
  • value — цена.

Ответ 200

json
{
  "success": true,
  "message": "Prices imported successfully",
  "stats": {
    "prices_saved": 25,
    "duration": "0.3s"
  }
}

POST /api/v1/import/image

Загрузка изображения файлом (не по ссылке). Файл сохраняется на сервере в каталоге клиента; в ответе возвращается URL для подстановки в product.images при импорте каталога. Дедупликация по SHA256: при той же контрольной сумме файл не дублируется — возвращается URL уже сохранённого изображения (как при импорте каталога с URL картинок).

Авторизация: заголовки X-Client-ID и X-Client-Secret (как у остальных импортных запросов).

Тело: multipart/form-data. Поле с файлом — image или file. Максимальный размер файла — 10 МБ.

Поддерживаемые типы загрузки: image/jpeg, image/png, image/gif, image/webp. Все сохраняются как JPEG (webp и остальные конвертируются, не переименование).

Ответ 200

json
{
  "url": "https://gosync.kz/api/v1/product-image/CLIENT_ID/images/ab/abcdef0123....jpg",
  "path": "CLIENT_ID/images/ab/abcdef0123....jpg"
}
  • url — полный URL (если задан PUBLIC_URL на сервере) или путь от корня сайта; файл хранится по SHA256 в каталоге images/{2 hex}/{hash}.jpg. Это значение можно передавать в product.images при импорте каталога.
  • path — суффикс после /api/v1/product-image/: client_id + /images/....

Изображения отдаются по GET /api/v1/product-image/{client_id}/images/{подпапка}/{hash}.jpg (публично, без авторизации).


Частичное обновление

  • Каталог: при full_replace: false — обновление по коду (склады, категории, виды цен) и по product_id (товары). Отправляйте только изменённые сущности.
  • Остатки (inventory) и цены (prices): при full_replace: false или без поля — дельта: обновляются только переданные пары (склад+товар, товар+вид цен). При full_replace: true — полная замена: сначала очищаются все остатки или все цены по клиенту, затем вставляется только то, что в запросе (полный срез из 1С без хранения дельты).