# Загрузка через REST API
Есть ситуации, когда использование товарного каталога YML невозможно:
- Слишком много товаров в базе (больше 200 000).
- Слишком большой файл XML-файл (больше 300 мегабайт).
- Часто появляются новые товары (в небольших количествах) и часто товары заканчиваются на складе (тоже в небольших количествах), поэтому загружать сотни тысяч товаров ради изменения нескольких сотен расточительно по трафику и ресурсам.
- Необходимо оперативно управлять наличием товаров (чаще, чем 1 раз в 3 часа).
Для этого разработан REST API.
Rate limit
Лимит запросов к API (Rate Limit) ограничен 40 запросами в минуту.
Лимит на вес запроса к API (Weight Limit) ограничен 35 мегабайтами на запрос.
Для On-premise лимитов нет.
# Порядок импорта
Обратите внимание – загружать товары можно только после выполнения подготовительных загрузок категорий и городов.
Последовательность шагов:
- Загрузка информации о категориях.
- Загрузка информации о городах/локациях.
- Первичная загрузка всех товаров.
- Итеративное обновление товарного каталога по мере необходимости.
# Загрузка категорий
XML
Не используйте этот метод, если используете способ загрузки товаров через YML/XML.
Прежде, чем загружать товары, необходимо загрузить в базу данных актуальный перечень категорий. Загружайте только те категории, которые используются в товарах (и промежуточные элементы дерева категорий). Нет смысла загружать конечные элементы дерева категорий (листья), в которых нет товаров.
# Описание метода
POST https://api.rees46.ru/import/categories
Необходимо указать заголовок:
Content-Type: application/json
Данные отправляются в виде JSON-строки, которая является телом запроса.
# Жизненный цикл запроса
- Сервер API REES46 принимает запрос.
- Выполняет первичную проверку доступа (
shop_id,shop_secret). Еслиshop_idиshop_secretне соответствуют существующим, сервер возвращает ошибку400 Bad request. - Отправляет задачу в фоновую обработку.
- Возвращает код
204 No body. - В случае успешной обработки фоновой задачи ничего не происходит. Задача обрабатывается быстро, поэтому спустя минуту уже можно загружать информацию о товарах.
- В случае ошибочной обработки фоновой задачи приходит уведомление на адрес электронной почты сотрудников, подписанных на технические уведомления.
# Структура данных
{
"shop_id": "...",
"shop_secret": "...",
"categories": [{category}, {category}, ...]
}
Структура информации о категории:
{
"id": "...", // String. Required
"name": "...", // String. Required
"parent": "...", // String or null. Optional
"url": "...", // String. Optional
"alias": "..." // String. Optional
}
XML
Если не указывать url, в стандартном шаблоне быстрого поиска категория выводиться не будет. Базовая механика предусматривает переход на страницу категории при клике. При этом в ответе API категории будут возвращаться, что позволит вывести их в кастомном или самописном шаблоне.
Вложенность подкатегорий не ограничена.
# Пример тела запроса
{
// Shop key, берется в личном кабинете на экране настроек магазина
"shop_id": "eehj3eu84299kg5ghw5a6743r8",
// Secret key, берется в личном кабинете на экране настроек магазина
"shop_secret": "pmd5362597thrgq8k256ep01t0",
// Список категорий
"categories": [
{
"id": "1",
"name": "Главная категория",
"parent": null,
"url": "https://mysite.com/catalog"
},
{
"id": "2",
"name": "Одежда",
"parent": "1",
"url": "https://mysite.com/catalog/apparel"
},
{
"id": "3",
"name": "Велосипеды",
"parent": "1",
"url": "https://mysite.com/catalog/bicycles"
},
{
"id": "100",
"name": "Детские",
"parent": "3",
"url": "https://mysite.com/catalog/bicycles/child",
"alias": "bicycles/child"
}
]
}
# Загрузка локаций
XML
Не используйте этот метод, если используете способ загрузки товаров через YML/XML.
Прежде, чем загружать товары, необходимо загрузить в базу данных актуальный перечень локаций. Загружайте только те локации, которые используются в товарах (и промежуточные элементы дерева локаций). Нет смысла загружать конечные элементы дерева локаций (листья), в которых нет товаров.
# Описание метода
POST https://api.rees46.ru/import/locations
Необходимо указать заголовок:
Content-Type: application/json
Данные отправляются в виде JSON-строки, которая является телом запроса.
# Жизненный цикл запроса
- Сервер API REES46 принимает запрос.
- Выполняет первичную проверку доступа (
shop_id,shop_secret). Еслиshop_idиshop_secretне соответствуют существующим, сервер возвращает ошибку400 Bad request. - Отправляет задачу в фоновую обработку.
- Возвращает код
204 No body. - В случае успешной обработки фоновой задачи ничего не происходит. Задача обрабатывается быстро, поэтому спустя минуту уже можно загружать информацию о товарах.
- В случае ошибочной обработки фоновой задачи приходит уведомление на адрес электронной почты сотрудников, подписанных на технические уведомления.
# Структура данных
{
"shop_id": "...",
"shop_secret": "...",
"locations": [{location}, {location}, ...]
}
Структура информации о локации:
{
"id": "...", // String. Required
"name": "...", // String. Required
"parent": "...", // String || Null. Required
"type": "...", // String. Optional
"group": "...", // String or Array of string. Optional
"discount_percent ": "..." // Optional,
"search_level_up": "..." // Integer. Optional
}
Обратите внимание
Как считается discount_percent при отсутствии значения (или самого параметра):
На корневом уровне товара:
- Если параметр указан — используется напрямую.
- Если параметр не указан, но есть
oldpriceиprice— значение вычисляется как целая часть от((oldprice - price) / oldprice) * 100(путём округления вниз до целого).
На уровне локаций:
- Работает по тем же правилам, что и на корневом уровне.
- Если в локации не указаны
oldpriceилиprice, для расчёта используются значения из корня товара.
Вложенность элементов не ограничена.
# Пример тела запроса
{
// Shop key, берется в личном кабинете REES46 на экране настроек магазина
"shop_id": "eehj3eu84299kg5ghw5a6743r8",
// Secret key, берется в личном кабинете REES46 на экране настроек магазина
"shop_secret": "pmd5362597thrgq8k256ep01t0",
// Список локаций
"locations": [
{
"id": "1",
"name": "Москва",
"parent": null,
"type": "city",
"group": "ДенежныеГорода",
"discount_percent ": 5
},
{
"id": "145",
"name": "Пункт выдачи на Арбате",
"parent": "1",
"type": "store",
"search_level_up": 1
},
{
"id": "2",
"name": "Санкт-Петербург",
"parent": null,
"type": "city",
"group": "ДенежныеГорода",
"discount_percent ": 5
},
{
"id": "3",
"name": "Приморский край",
"parent": "1",
"type": "state",
"search_level_up": 0
},
{
"id": "4",
"name": "Владивосток",
"parent": "3",
"type": "city",
"group": "ДальнийВосток",
"discount_percent ": 5,
"search_level_up": 1
}
]
}
# Загрузка товаров
# Описание метода
PUT https://api.rees46.ru/import/products
Необходимо указать заголовок:
Content-Type: application/json
Данные отправляются в виде JSON-строки, которая является телом запроса.
Есть следующие виды запросов:
| Название операции | Тип HTTP запроса | Описание |
|---|---|---|
| Добавление/изменение | PUT | Добавить новые товары, не отключая существующие, либо обновить существующие. |
| Синхронизация | PATCH | Синхронизировать наличие товаров. |
| Удаление | DELETE | Удалить товары, перечисленные в запросе (отметить как "не в наличии"). |
# Жизненный цикл запроса
- Сервер API REES46 принимает запрос.
- Выполняет первичную проверку доступа (
shop_id,shop_secret). Еслиshop_idиshop_secretне соответствуют существующим, сервер возвращает ошибку400 Bad request. - Отправляет задачу в фоновую обработку.
- Возвращает код
204 No body. - В случае успешной обработки фоновой задачи ничего не происходит. Задача обрабатывается быстро, поэтому спустя минуту уже можно загружать информацию о товарах.
- В случае ошибочной обработки фоновой задачи приходит уведомление на адрес электронной почты сотрудников, подписанных на технические уведомления.
Обратите внимание
Все ключи регистрозависимы.
# Описание данных в запросе
{
"shop_id": "...",
"shop_secret": "...",
"items": [{item1}, {item2}, ...]
}
Пример структуры объекта товара item:
{
"id": "string", // required
"available": true,
"categories": ["string", 1], // required, array of strings or integers
"picture": "https://example.com/image.jpg", // URL, required, max. 500 characters
"name": "string", // required
"price": 99.99, // required, >0
"url": "https://example.com/product", // required
"oldprice": 120.00,
"params": [
{
"name": "weight", //required
"value": [70.5], //Array.Required
"unit": "kg", // Optional
"priority": 1, // Optional
"searchable": true
},
{
"name": "color",
"value": ["red", "blue"],
"unit": null,
"priority": 2,
"searchable": false
}
],
"group_id": "group123",
"type_prefix": "prefix",
"brand": "Brand Name",
"brand_picture": "https://example.com/brand.jpg",
"vendor_code": "ABC123",
"barcode": "1234567890123",
"model": "Model Name",
"description": "Product description",
"merchant": ["First merchant's name","second merchant's name", "third merchant's name"],
"tags": ["tag1", "tag2"],
"stock_quantity": 10,
"discount_percent": 15,
"gift": "Gift Name",
"installment": 12,
"promocode": "DISCOUNT10",
"price_with_promocode": 89,
"deeplink_android": "app://product/123",
"deeplink_ios": "app://product/123",
"bonuses_accrual_allowed": true,
"bonuses_spending_allowed": false,
"discounts_allowed": true,
"accessories": ["Accessory1", "Accessory2"],
"customer_recommendations": ["Product1", "Product2"],
"seasonality": [1, 2, 12], // array of numbers 1-12
"rating": 3, // number 1-5
"leftovers": "few",
"is_new": true,
"fashion": {
"gender": "m",
"type": "clothing",
"sizes": ["S", "M", 42],
"colors": [
{
"color": "red",
"picture": "https://example.com/red.jpg"
}
],
"feature": "adult" // e.g., 'adult'
},
"child": {
"type": "toy",
"gender": "f",
"age": {
"min": 3,
"max": 7
}
},
"jewelry": {
"gender": "f",
"color": "gold",
"metal": "gold",
"gem": "diamond",
"ring_sizes": [6, "7.5"],
"bracelet_sizes": ["S", "M"],
"chain_sizes": [40, 50]
},
"cosmetic": {
"gender": "f",
"hypoallergenic": true,
"periodic": false,
"skin": {
"part": ["face", "hands"],
"type": ["dry", "oily"],
"condition": ["acne", "wrinkles"]
},
"hair": {
"type": ["curly", "straight"],
"condition": ["damaged", "dry"]
},
"nail": {
"type": "gel",
"polish_color": "red"
},
"perfume": {
"aroma": "floral",
"family": "woody"
},
"professional": true
},
"pharmacy": {
"volumes": [
{
"value": 100,
"price": 19.99
}
]
},
"book": {
"author": "Author Name",
"publisher": "Publisher Name",
"series": "Book Series",
"editor": "Editor Name",
"illustrator": "Illustrator Name",
"year": 2022, // 1700 < year < current year
"isbn": ["978-3-16-148410-0"]
},
"realty": {
"action": "rent",
"type": "apartment",
"space": {
"min": 50,
"max": 120,
"final": 100
}
},
"auto": {
"vds": "engine oil",
"periodic": true,
"compatibility": [
{
"brand": "Toyota",
"model": "Camry"
}
]
},
"fmcg": {
"hypoallergenic": false,
"periodic": true
},
"pets": {
"periodic": true,
"breed": "Labrador",
"type": "dog",
"age": "puppy",
"size": "large"
},
"date": "2025-03-03T12:00:00Z", // valid date
"price_margin": 20, // 0-100
"ignored": false
}
Примите во внимание
При обработке url к ссылке добавляются параметры вида recommended_by, recommended_code и т.д.
Они необходимы для работы трекинга событий и построения аналитики.
Если вам нужно передать в ссылке собственные параметры, их требуется закодировать.
В противном случае некоторые символы будут некорректно обработаны, например, согласно спецификации RFC3986 знак + распознается как пробел.
Если вам нужно, чтобы при переходе по ссылке в параметре передавался знак +, то его нужно экранировать в %2B.
Пример:
http://test.com?test=+-!ABC -> http://test.com?test=%2B-%21ABC
Нужно учитывать
- Если ключ параметра пришёл пустым, параметр игнорируется и не добавляется в список параметров товара
- При отсутствии параметра
discount_percentи наличииoldprice, первый будет автоматически рассчитан по формуле: целая часть от((oldprice - price) / oldprice) * 100(получается путём округления вниз до целого)
# Особенности location
Объект "Цена и наличие в локации" показывает, что товар есть в наличии, в определенной локации и его цена отличается от базовой цены. Если
цена в объекте не указана, то для указанной локации будет использоваться базовая цена. Если объект "Цена и наличие в локации" указан, то во
всех других локациях, которые не перечислены для данного товара в свойстве locations, товар будет считаться не в наличии.
{
"location": "...", // String. Required
"price": ..., // Float (positive). Optional.
"oldprice": ..., // Float (positive). Optional.
"merchant": ["...", "..."], // Array of strings. Optional.
"stock_quantity": ..., // Int (positive). Optional.
"sizes": ["...", "..."], // Array of string. Optional.
"weight": ..., // Int (positive). Optional.
"delivery_types": {
"store": ..., // Int (positive). Available in store
"delivery": ..., // Int (positive). Available in delivery
"warehouse": ... // Int (positive). Available in warehouse
}, // Object. Optional
}
# Особенности delivery_types
Объект "Типы доставки" показывает, что товар доступен для покупки в магазине или со склада.
{
"delivery_type_1": ..., // Int. Required
"delivery_type_2": ..., // Int. Required
"...": ...,
}
# Особенности params
Пример вложенной структуры информации о параметрах params:
{
"name": "...", // String. Required
"value": ["...", "..."], // Array. Required
"unit": "...", // String. Optional
"priority": ..., // Int. Optional
"searchable": ..., // Boolean (true, false)
}
# Нишевые параметры
Для обогащения пользовательских профилей и усиления эффекта персонализации рекомендуется добавлять нишевые параметры товаров в секцию offer.
- Автотовары
- Книги
- Товары для детей
- Косметика и парфюмерия
- Недвижимость
- Одежда, обувь, аксессуары
- Строительные материалы и инструмент
- Товары для взрослых
- Товары для животных
- Товары повседневного спроса (FMCG)
- Фармацевтика и медицина
- Ювелирные украшения
# Пример структуры
Лимит
Рекомендуется отправлять не более 5000 товаров в одном запросе.
Ниже представлен пример с заполненными данными и пояснениями:
{
// Shop key, берется в личном кабинете REES46 на экране настроек магазина
"shop_id": "eehj3eu84299kg5ghw5a6743r8",
// Secret key, берется в личном кабинете REES46 на экране настроек магазина
"shop_secret": "pmd5362597thrgq8k256ep01t0",
// Список товаров
"items": [
// Товар 1
{
// Идентификатор товара в магазине
"id": "6335",
// Идентификатор группы товаров в магазине. Если передаются варианты товаров, этот параметр позволяет объеденить их в один товар
"group_id": "633",
// Название
"name": "Велосипед",
// Цена
"price": 13000,
// Цена с учётом применения промокода
"price_with_promocode": 12000,
// Старая цена
"oldprice": 16000,
// Валюта цены
"currency": "RUB",
// URL товара, без UTM-меток и прочих параметров отслеживания источников перехода
"url": "https://myste.com/products/6335.html",
// URL товара в приложении Android
"deeplink_android": "https://myste.com/products/6335.html",
// URL товара в приложении Ios
"deeplink_ios": "https://myste.com/products/6335.html",
// URL фотографии товара
"picture": "https://mysite.com/pictures/6335.jpg",
// Товар в наличии
"available": true,
// Массив идентификаторов категорий, в которых лежит товар (не хлебные крошки, только конечные категории)
"categories": ["17", "3"],
// Штрих-код товара
"barcode": "17333838374318",
// Маржинальность товара 10%
"price_margin": 10,
// Наличие товаров в определенных городах: доступен только в Москве и СПб
"locations": [
// Есть в наличии в Москве и его цена равна базовой
{
"location": "msk",
"delivery_types": {
"shop": 10, // В магазине 10 шт.
"stock": 50 // На складе 50 шт.
}
},
// Есть в наличии в СПб и его цена отличается
{
"location": "spb",
"price": 12500
}
],
// Производитель
"brand": "Marine",
// Характеризующие теги
"tags": ["alluninium", "sport"],
// Детский велосипед
"is_child": true,
// Параметры товара
"params": [
{
"name": "интерфейс",
"value": ["bluetooth", "wi-fi"]
},
{
"name": "энергопотребление",
"value": [23],
"unit": "вт"
},
{
"name": "Сим карта",
"value": ["E-sim"],
"priority": 20
},
{
"name": "Цвет лейбла",
"value": "Синий",
"searchable": false // Технический параметр исключается из блока filters
}
],
// Мерчант
"merchant": "abc123xyz789",
// Дата добавления|обновления
"creation_date": "2022-01-01",
// Наличие подарка
"gift": true,
// Информация о рассрочке
"installment": 36,
// Информация о скидке
"discount_percent": 50,
// Информация о промокоде
"promocode": "Sale50",
// Начисление бонусов за товар разрешено
"bonuses_accrual_allowed": true,
// Списание бонусов за товар разрешено
"bonuses_spending_allowed": true,
// Применение скидки на товар разрешено
"discounts_allowed": true
},
// Товар 2
{
"id": "133",
"name": "Куртка красная",
"price": 123000,
"oldprice": 132000,
"currency": "RUB",
"url": "https://myste.com/products/133.html",
"picture": "https://mysite.com/pictures/133.jpg",
"available": true,
"categories": ["33"],
// Доступен только в Москве
"locations": [
{ "location": "msk" }
],
"brand": "Racoon",
"tags": ["winter", "sport"],
// Это одежда
"is_fashion": true,
"fashion": {
// Мужская
"gender": "m",
// В размерах 48, 50, 52 российской размерной сетки
"sizes": ["48", "50", "52"],
// Тип: куртка
"type": "jacket"
},
// Дата добавления|обновления
"date": "2022-01-01"
}
]
}
# Особенности отправки DELETE запроса
При отправке запроса типа DELETE (удаление товаров из платформы) достаточно перечислить идентификаторы товаров, которые необходимо удалить. Пример:
{
"shop_id": "eehj3eu84299kg5ghw5a6743r8",
"shop_secret": "pmd5362597thrgq8k256ep01t0",
"items": ["635", "3373", "75778"]
}
# Особенности отправки PATCH запроса
При отправке запроса типа PATCH (синхронизация наличия товаров в базе данных платформы) достаточно перечислить идентификаторы товаров, которые необходимо пометить как "в наличии". Товары из текущей базы данных платформы, идентификаторы которых не включены в PATCH запрос, будут помечены как "не в наличии".
Пример:
{
"shop_id": "eehj3eu84299kg5ghw5a6743r8",
"shop_secret": "pmd5362597thrgq8k256ep01t0",
"items": ["635", "3373", "75778"]
}
# Webhook запросы
Для автоматизации процесса импорта данных о товарах можно использовать функционал webhook запросов.
# Импорт категорий с webhook параметром
{
"shop_id": "...",
"shop_secret": "...",
"categories": ["category_id_1", "category_id_2", "..."],
"webhook": "https://site.com/webhook"
}
# Импорт локаций с webhook параметром
{
"shop_id": "...",
"shop_secret": "...",
"locations": ["location_id_1", "location_id_2", "..."],
"webhook": "https://site.com/webhook"
}
# Импорт товаров с webhook параметром
{
"shop_id": "...",
"shop_secret": "...",
"items": ["item_id_1", "item_id_2", "..."],
"webhook": "https://site.com/webhook"
}
После того, как запрос будет обработан, на указанный вебхук будет отправлен POST запрос c типом Content-Type: application/json
Примеры:
{
"status": "success"
}
{
"status": "error",
"message": "MESSAGE"
}