Skip to content

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

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

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

Остатки и цены: по умолчанию дельта — обновляются только переданные пары (склад+товар, товар+вид цен); остальное не трогается. При full_replace: true чистка не глобальная по клиенту: только склады / виды цен, которые есть в этом запросе.

Запросfull_replace: trueНе трогает
catalogвсе товары клиента → Удален, затем upsert из телаостатки и цены (строки в БД остаются)
inventoryостатки только по store_id из запроса, потом вставка срезадругие склады, цены, каталог
pricesцены только по price_id из запроса, потом вставка срезадругие виды цен, остатки, каталог
stocks (legacy)остатки по store_id + цены по marketplace из запросасклады и виды, которых нет в теле

Склад / вид цен, которого нет ни в одной строке запроса, при full_replace не очищается. Одна 1С на все склады: шлите в одном inventory все store_id (или пачками по складу с полным срезом каждого) — товары, которые просто не пришли, на этих складах остатка не оставят.

Центральный полный каталог с full_replace — нормальный способ вычистить мусор в номенклатуре. Остатки и цены от этого не сносятся; SKU не из среза на витрине выключается как Удален.

Новые API: inventory и prices

Для новых интеграций: POST /api/v1/import/inventory (остатки) и POST /api/v1/import/prices (цены). В каталоге обязательно передавайте price_types. Без видов цен импорт цен пропустит строки с неизвестным price_id. Для старых клиентов на POST /api/v1/import/stocks 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полная замена каталога: все товары клиента помечаются как Удален, затем создаются/обновляются только переданные в запросе. Остатки и цены каталог не трогает — полный сброс остатков/цен только через full_replace в POST /api/v1/import/inventory и POST /api/v1/import/prices. Удобно при выгрузке каталога по точкам/складам отдельными запросами: один full_replace на первой пачке, остальные — дельта без флага.
    • 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)

Импорт остатков и цен по складам и товарам в одном запросе. Склады и товары должны быть ранее импортированы через каталог. Эндпоинт работает — оставлен для существующих интеграций, не отключали.

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

Новые подключения: POST /api/v1/import/inventory (остатки) и POST /api/v1/import/prices (цены по видам цен). Здесь одна цена на товар на маркетплейс; разные цены по складам не поддерживаются.

Тело запроса

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 — очистить остатки только по складам из запроса и цены только по видам цен (marketplace) из запроса, затем вставить только из запроса; иначе дельта.
  • 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полная замена остатков по складу: удаляются все остатки только по складам (store_id), присутствующим в запросе; другие точки не трогаются. Затем вставляются только переданные строки. Удобно для выгрузки из 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полная замена цен по виду цен: удаляются цены только по видам цен (price_id), присутствующим в запросе; другие виды (другие аптеки/типы) не трогаются. Справочник видов цен не меняется. Затем вставляются только переданные строки. Удобно для выгрузки из 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 в inventory — очищаются остатки только по складам из запроса; в prices — цены только по видам цен из запроса.