Коротко. Яндекс Маркет API позволяет автоматизировать каталог, карточки, цены, остатки, заказы, FBS-документы, отзывы, вопросы, чаты и отчёты. Но рабочая интеграция — это не один HTTP-запрос, а цепочка: категории → характеристики → товары → карточки → цены → карантин → остатки → заказы → отгрузки → уведомления. Это третий материал серии по маркетплейсам — рядом Wildberries API и Ozon Seller API.
Для кого эта статья и какой интент закрывает
Для селлера, интегратора или разработчика, которому нужно связать Яндекс Маркет с 1С, МойСклад, CRM, ERP, PIM, Google Sheets, n8n, кастомной базой товаров или собственным backend. Статья не пересказывает документацию — это рабочая архитектура, API-методы, JSON-примеры, n8n workflow и список ошибок, которые лучше поймать до запуска. Если нужна бизнес-картина «зачем и что это даёт», смотрите общий материал автоматизация Яндекс Маркета для селлера; здесь — техническая сторона.
Пользователь хочет понять не «что такое API», а как реально подключить Маркет к своей системе: какие методы нужны, какие данные хранить, где ломается интеграция, как не упереться в лимиты и не сломать карточки, цены и заказы.
Что можно автоматизировать через Яндекс Маркет API
Официальный Partner API помогает управлять ассортиментом и ценами, обрабатывать заказы, обновлять остатки и подключать уведомления о событиях. Базовые разделы: товары, остатки, цены, акции, заказы, FBS-отгрузки, ярлыки, поставки, возвраты, отчёты, отзывы, вопросы, буст продаж, индекс качества, чаты и склады.
| Контур | Что автоматизируем | Основные методы |
|---|---|---|
| Категории | дерево категорий, листовая категория | POST /v2/categories/tree |
| Характеристики | обязательные и фильтруемые параметры | POST /v2/category/{categoryId}/parameters |
| Товары | создание и обновление товаров | POST /v2/businesses/{businessId}/offer-mappings/update |
| Карточки | категорийные характеристики | POST /v2/businesses/{businessId}/offer-cards/update |
| Цены для кабинета | цена во всех магазинах | POST /v2/businesses/{businessId}/offer-prices/updates |
| Цены магазина | отдельная цена в магазине | POST /v2/campaigns/{campaignId}/offer-prices/updates |
| Остатки | остатки FBS, Express, DBS | PUT /v2/campaigns/{campaignId}/offers/stocks |
| Условия продажи | доступность, НДС, кванты | POST /v2/campaigns/{campaignId}/offers/update |
| Заказы | список и статусы заказов | POST /v1/businesses/{businessId}/orders |
| FBS | коробки, ярлыки, акты, подтверждение отгрузки | методы FBS, labels, shipments |
| Уведомления | события по заказам, возвратам, чатам, отзывам | API-уведомления (webhook) |
Главная схема интеграции
Конвейер с ключевой развилкой на ценах (карантин) и единым контуром логов/алертов.
- Источник: ERP / CRM / PIM / Google Sheets / 1С → нормализация данных.
- Справочники Маркета:
/v2/categories/tree,/v2/category/{categoryId}/parameters. - Валидация товара по справочникам и обязательным характеристикам.
- Каталог:
offer-mappings/update(товар) +offer-cards/update(категорийные характеристики). - Проверка карточки после обновления.
- Цены: бизнес-цены и/или цены магазина → проверка карантина.
- Остатки:
PUT /v2/campaigns/{campaignId}/offers/stocks. - Заказы и FBS → подтверждение отгрузки.
- API-уведомления вместо постоянного polling.
- Логи, алерты, отчёты по всем шагам.
Ключевая модель данных: businessId, campaignId, offerId
В Яндекс Маркете нельзя строить интеграцию, не разделяя кабинет, магазин и SKU.
| Поле | Что означает | Где используется |
|---|---|---|
businessId | кабинет продавца | каталог, карточки, бизнес-цены, отзывы, вопросы, чаты |
campaignId | магазин/кампания размещения | остатки, заказы, условия продажи, цены магазина, FBS |
offerId | ваш SKU | товар, цена, остаток, заказные позиции |
marketCategoryId | листовая категория Маркета | создание и обновление товаров |
marketSku | SKU карточки на Маркете | привязка к существующей карточке |
Минимальная таблица для интеграции:
{
"businessId": 123456,
"campaignId": 7891011,
"offerId": "NODB-TSHIRT-BLACK-M",
"vendorCode": "TSHIRT-BLACK-M",
"marketCategoryId": 7811901,
"marketSku": null,
"warehouseId": 111222,
"lastCatalogSyncAt": "2026-06-13T10:00:00+03:00",
"lastPriceSyncAt": null,
"lastStockSyncAt": null,
"status": "draft"
}
campaignId там, где нужен businessId, или наоборот. Особенно часто на ценах: цена «для всех магазинов» идёт через businessId, а цена конкретного магазина — через campaignId.Авторизация: используйте API-Key, не OAuth
Для новых интеграций используйте API-Key. Он привязан к кабинету, действует для всех магазинов кабинета и передаётся в заголовке Api-Key. OAuth в документации помечен как устаревший способ.
Api-Key: {{$credentials.yandexMarket.apiKey}}
Content-Type: application/json
Правила безопасности:
- не вставляйте API-Key в workflow JSON;
- не храните ключ в Google Sheets;
- не публикуйте ключ в скриншотах;
- используйте credentials / env-переменные;
- выдавайте токену только нужные доступы, а не всегда
all-methods.
Лимиты: почему в Яндекс Маркете важна ошибка 420
Самое важное для production — не больше 4 параллельных запросов. При превышении Маркет возвращает 420 Enhance Your Calm. Дополнительно: в ответах приходят заголовки ресурсных лимитов; успешные 2xx и клиентские 4xx уменьшают лимит; ошибки 5xx лимит не уменьшают; максимальный размер тела запроса — 512 КБ; большие списки нужно передавать батчами и читать через пагинацию.
Практическое правило для n8n/backend:
Concurrency: 1–3 запроса одновременно
Batch size для товаров: 50–100
Batch size для цен: до 500, но лучше 100–300
Batch size для остатков: до 2000, но лучше 500–1000
Retry: только для 420/5xx, не для validation error
Простая логика обработки статусов
offerId.Автоматизация товаров
Шаг 1. Получить дерево категорий
POST https://api.partner.market.yandex.ru/v2/categories/tree
{
"language": "RU"
}
Что сохранить (нужна листовая категория — без дочерних):
{
"categoryId": 7811901,
"name": "Футболки",
"isLeaf": true,
"parentId": 7811888
}
Шаг 2. Получить характеристики категории
POST https://api.partner.market.yandex.ru/v2/category/{categoryId}/parameters?businessId={businessId}
Что важно в ответе: id, name, type, required, filtering, distinctive, multivalue, allowCustomValues, values. Пример нормализованного справочника:
{
"categoryId": 7811901,
"parameters": [
{
"id": 14871214,
"name": "Цвет товара",
"type": "ENUM",
"required": true,
"filtering": true,
"distinctive": true,
"allowCustomValues": false,
"values": [
{ "id": 61577, "value": "черный" },
{ "id": 61576, "value": "белый" }
]
}
]
}
Шаг 3. Создать или обновить товар
POST https://api.partner.market.yandex.ru/v2/businesses/{businessId}/offer-mappings/update
Метод добавляет товары в каталог и передаёт листовую категорию, категорийные и основные характеристики, цены в кабинете. Для нового товара обязательны:
offerId
name
marketCategoryId
pictures
vendor
description
Пример payload:
{
"offerMappings": [
{
"offer": {
"offerId": "NODB-TSHIRT-BLACK-M",
"name": "Футболка мужская хлопковая черная M",
"marketCategoryId": 7811901,
"pictures": [
"https://example.com/images/tshirt-black-main.jpg",
"https://example.com/images/tshirt-black-back.jpg"
],
"vendor": "Nodbot",
"description": "Мужская футболка из хлопка. Подходит для повседневной носки, спорта и базового гардероба.",
"barcodes": [
"4601234567890"
],
"manufacturerCountries": [
"Россия"
],
"weightDimensions": {
"length": 25,
"width": 20,
"height": 3,
"weight": 0.25
},
"vendorCode": "TSHIRT-BLACK-M",
"parameterValues": [
{
"parameterId": 14871214,
"valueId": 61577,
"value": "черный"
},
{
"parameterId": 14871335,
"value": "M"
}
],
"basicPrice": {
"value": 1490,
"currencyId": "RUR"
},
"purchasePrice": {
"value": 650,
"currencyId": "RUR"
}
}
}
]
}
Что проверить до отправки
offerIdуникальный и не использовался для другого товара;offerIdбез пробелов в начале/конце;- категория листовая, обязательные характеристики заполнены;
- ENUM-значения переданы с правильным
valueId; - фото доступны по HTTPS;
- название не длиннее 256 символов, описание — не длиннее 6000;
- нет рекламных слов и ссылок в описании;
- габариты, вес и штрихкод заполнены и валидны;
- batch не превышает 512 КБ.
Шаг 4. Обновить категорийные характеристики
POST https://api.partner.market.yandex.ru/v2/businesses/{businessId}/offer-cards/update
{
"offersContent": [
{
"offerId": "NODB-TSHIRT-BLACK-M",
"categoryId": 7811901,
"parameterValues": [
{
"parameterId": 14871214,
"valueId": 61577,
"value": "черный"
},
{
"parameterId": 14871335,
"value": "M"
},
{
"parameterId": 200,
"value": "Футболка Nodbot базовая"
}
]
}
]
}
Что важно: основные параметры товара меняются через offer-mappings/update, категорийные характеристики — через offer-cards/update; обновление в каталоге занимает до нескольких минут; 200 OK не всегда означает, что каждое значение принято — проверяйте карточку после обновления.
Объединение вариантов товара
Для объединения вариантов используется характеристика id: 200 — «Название группы вариантов».
Группа: Футболка Nodbot базовая
Вариант 1: черный / M
Вариант 2: черный / L
Вариант 3: белый / M
Для корректного объединения: товары в одной категории; группа вариантов совпадает; отличительные характеристики различаются; неотличительные — одинаковы.
Автоматизация цен
У Маркета два уровня цен — важно не перепутать businessId и campaignId.
| Уровень | Метод | Когда использовать |
|---|---|---|
| Цена для всех магазинов кабинета | POST /v2/businesses/{businessId}/offer-prices/updates | одна цена для всех магазинов |
| Цена конкретного магазина | POST /v2/campaigns/{campaignId}/offer-prices/updates | включены отдельные цены по магазинам |
Цена для всех магазинов
{
"offers": [
{
"offerId": "NODB-TSHIRT-BLACK-M",
"price": {
"value": 1490,
"currencyId": "RUR",
"discountBase": 1990
}
}
]
}
Цена для отдельного магазина
{
"offers": [
{
"offerId": "NODB-TSHIRT-BLACK-M",
"price": {
"value": 1450,
"currencyId": "RUR",
"discountBase": 1990
}
}
]
}
Защита от ценовых ошибок
Перед отправкой цены в API нужен guardrail:
const minMargin = 0.18;
const purchasePrice = Number($json.purchasePrice);
const newPrice = Number($json.price);
const oldPrice = Number($json.oldPrice || 0);
if (!newPrice || newPrice <= 0) {
throw new Error('Некорректная цена');
}
const margin = (newPrice - purchasePrice) / newPrice;
if (margin < minMargin) {
throw new Error(`Маржа ниже минимума: ${(margin * 100).toFixed(1)}%`);
}
if (oldPrice && newPrice < oldPrice * 0.5) {
throw new Error('Цена снизилась больше чем на 50%, нужна ручная проверка');
}
return [{ json: { ...$json, margin } }];
Карантин цен
Если цена изменилась слишком резко, товар может попасть в карантин. Правильный workflow:
1. Рассчитать экономику и тарифы.
2. Отправить новую цену.
3. Проверить price quarantine.
4. Если цена ошибочная — исправить.
5. Если цена корректная — подтвердить карантин вручную или по строгому правилу.
Автоматизация остатков
PUT https://api.partner.market.yandex.ru/v2/campaigns/{campaignId}/offers/stocks
Доступно для FBS, Express и DBS. Пример:
{
"skus": [
{
"sku": "NODB-TSHIRT-BLACK-M",
"items": [
{
"count": 42,
"updatedAt": "2026-06-13T12:00:00+03:00"
}
]
}
]
}
Практические правила
- SKU должен совпадать символ в символ;
557722и0557722— разные SKU;- остаток
0допустим и означает обнуление; countне должен быть отрицательным;- при группах складов передавайте остаток по правилам группы;
- не отправляйте остатки одновременно из нескольких систем;
- храните
lastStockSyncAtи источник остатка.
Автоматизация условий продажи
POST https://api.partner.market.yandex.ru/v2/campaigns/{campaignId}/offers/update
Можно менять доступность товара в магазине, НДС и продажу квантами. Пример:
{
"offers": [
{
"offerId": "NODB-TSHIRT-BLACK-M",
"available": true,
"vat": "VAT_20_120",
"quantum": {
"minQuantity": 1,
"stepQuantity": 1
}
}
]
}
Автоматизация заказов и FBS
Для новых интеграций ориентируйтесь на актуальный метод:
POST /v1/businesses/{businessId}/orders
/v2/campaigns/{campaignId}/orders помечены устаревшими. Старый метод списка заказов должен стать нестабильным с 18 января 2027 и отключиться 12 апреля 2027.Что хранить по заказу
{
"orderId": 123456789,
"status": "PROCESSING",
"substatus": "STARTED",
"campaignId": 7891011,
"businessId": 123456,
"items": [
{
"offerId": "NODB-TSHIRT-BLACK-M",
"count": 1,
"price": 1490,
"vat": "VAT_20_120",
"hasCis": false
}
],
"shipmentId": 555444333,
"createdAt": "2026-06-13T12:10:00+03:00"
}
FBS workflow
- Новый заказ → получить детали заказа.
- Проверить остаток и маркировку.
- Передать коробки / грузоместа.
- Передать коды маркировки, если нужны.
- Получить ярлыки и сформировать лист подбора.
- Подготовить акт.
- Подтвердить отгрузку.
- Обновить статус в ERP/CRM.
Что не стоит делать полностью автоматически: отменять заказы; переносить заказы; подтверждать спорные возвраты; отправлять неверные коды маркировки; подтверждать отгрузку до физической готовности заказа.
API-уведомления вместо постоянного polling
Маркет может отправлять POST-запросы на ваш URL при событиях: создание/изменение/отмена заказа и его статуса, заявка на отмену, возврат или невыкуп, новый отзыв, новый чат и сообщение в чате, начало/завершение спора.
Требования
- HTTPS с SSL-сертификатом от официального центра сертификации (self-signed не подходит);
- проверка IP-диапазонов Маркета;
- ответ на PING за 1 секунду;
- ответ на обычное уведомление за 10 секунд.
Минимальный ответ на проверочный PING:
{
"version": "1.0.0",
"name": "nodbot-yandex-market-webhook",
"time": "2026-06-13T12:00:00.000000000Z"
}
n8n workflow: создание товара + цена + остаток
Минимальный импортируемый workflow. Он не заменяет production-интеграцию, но показывает правильную структуру: входной webhook → валидация → создание товара → цена → остаток.
Перед импортом создайте credentials или env-переменные:
YANDEX_MARKET_API_KEY
YANDEX_MARKET_BUSINESS_ID
YANDEX_MARKET_CAMPAIGN_ID
{
"name": "Yandex Market API - Product Price Stock Sync",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "yandex-market-product-sync",
"responseMode": "responseNode"
},
"id": "WebhookTrigger",
"name": "Webhook - New Product",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
0
]
},
{
"parameters": {
"jsCode": "const item = $json;\n\nconst required = ['offerId', 'name', 'marketCategoryId', 'pictures', 'vendor', 'description', 'price', 'stock'];\nfor (const field of required) {\n if (item[field] === undefined || item[field] === null || item[field] === '') {\n throw new Error(`Missing required field: ${field}`);\n }\n}\n\nif (!Array.isArray(item.pictures) || item.pictures.length === 0) {\n throw new Error('pictures must be a non-empty array');\n}\n\nif (String(item.offerId).trim() !== String(item.offerId)) {\n throw new Error('offerId must not contain leading/trailing spaces');\n}\n\nif (String(item.name).length > 256) {\n throw new Error('name is too long');\n}\n\nif (String(item.description).length > 6000) {\n throw new Error('description is too long');\n}\n\nif (Number(item.price) <= 0) {\n throw new Error('price must be positive');\n}\n\nif (Number(item.stock) < 0) {\n throw new Error('stock must not be negative');\n}\n\nreturn [{ json: item }];"
},
"id": "ValidateInput",
"name": "Validate input",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
240,
0
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.partner.market.yandex.ru/v2/businesses/{{$env.YANDEX_MARKET_BUSINESS_ID}}/offer-mappings/update",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Api-Key",
"value": "={{$env.YANDEX_MARKET_API_KEY}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"offerMappings\": [\n {\n \"offer\": {\n \"offerId\": $json.offerId,\n \"name\": $json.name,\n \"marketCategoryId\": $json.marketCategoryId,\n \"pictures\": $json.pictures,\n \"vendor\": $json.vendor,\n \"description\": $json.description,\n \"barcodes\": $json.barcodes || [],\n \"manufacturerCountries\": $json.manufacturerCountries || [],\n \"weightDimensions\": $json.weightDimensions,\n \"vendorCode\": $json.vendorCode || $json.offerId,\n \"parameterValues\": $json.parameterValues || [],\n \"basicPrice\": {\n \"value\": Number($json.price),\n \"currencyId\": \"RUR\"\n }\n }\n }\n ]\n}"
},
"id": "CreateOrUpdateProduct",
"name": "Create/update product",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
500,
0
]
},
{
"parameters": {
"amount": 3,
"unit": "seconds"
},
"id": "WaitAfterProductUpdate",
"name": "Wait after product update",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
740,
0
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.partner.market.yandex.ru/v2/businesses/{{$env.YANDEX_MARKET_BUSINESS_ID}}/offer-prices/updates",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Api-Key",
"value": "={{$env.YANDEX_MARKET_API_KEY}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"offers\": [\n {\n \"offerId\": $node['Validate input'].json.offerId,\n \"price\": {\n \"value\": Number($node['Validate input'].json.price),\n \"currencyId\": \"RUR\",\n \"discountBase\": Number($node['Validate input'].json.discountBase || 0) || undefined\n }\n }\n ]\n}"
},
"id": "UpdatePrice",
"name": "Update business price",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
980,
0
]
},
{
"parameters": {
"method": "PUT",
"url": "=https://api.partner.market.yandex.ru/v2/campaigns/{{$env.YANDEX_MARKET_CAMPAIGN_ID}}/offers/stocks",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Api-Key",
"value": "={{$env.YANDEX_MARKET_API_KEY}}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"skus\": [\n {\n \"sku\": $node['Validate input'].json.offerId,\n \"items\": [\n {\n \"count\": Number($node['Validate input'].json.stock),\n \"updatedAt\": new Date().toISOString()\n }\n ]\n }\n ]\n}"
},
"id": "UpdateStocks",
"name": "Update stock",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1220,
0
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"ok\": true,\n \"offerId\": $node['Validate input'].json.offerId,\n \"message\": \"Product, price and stock sync was sent to Yandex Market API\"\n}"
},
"id": "Respond",
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1460,
0
]
}
],
"connections": {
"Webhook - New Product": {
"main": [
[
{
"node": "Validate input",
"type": "main",
"index": 0
}
]
]
},
"Validate input": {
"main": [
[
{
"node": "Create/update product",
"type": "main",
"index": 0
}
]
]
},
"Create/update product": {
"main": [
[
{
"node": "Wait after product update",
"type": "main",
"index": 0
}
]
]
},
"Wait after product update": {
"main": [
[
{
"node": "Update business price",
"type": "main",
"index": 0
}
]
]
},
"Update business price": {
"main": [
[
{
"node": "Update stock",
"type": "main",
"index": 0
}
]
]
},
"Update stock": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Code node: батчинг под лимит 512 КБ
Используйте перед HTTP Request, если отправляете много товаров:
const maxBytes = 480 * 1024; // запас до лимита 512 КБ
const offers = $input.all().map(i => i.json);
const batches = [];
let current = [];
function payloadSize(items) {
return Buffer.byteLength(JSON.stringify({ offerMappings: items }), 'utf8');
}
for (const offer of offers) {
const next = [...current, offer];
if (payloadSize(next) > maxBytes || next.length > 100) {
batches.push(current);
current = [offer];
} else {
current = next;
}
}
if (current.length) batches.push(current);
return batches.map((batch, index) => ({
json: {
batchIndex: index + 1,
batchSize: batch.length,
offerMappings: batch
}
}));
Production-чек-лист перед запуском
- API-Key создан и хранится в credentials/env.
- Проверен
apiAvailabilityдля магазина. businessIdиcampaignIdсохранены отдельно.- Настроен rate limiter: не более 4 параллельных запросов.
- Есть обработка
420 Enhance Your Calm. - Retry только для
420и5xx;400/422уходят в лог ошибок. - Тело запроса не превышает 512 КБ.
- Категории и характеристики обновляются по расписанию.
- Есть локальная валидация обязательных характеристик и защита от переиспользования
offerId. - Есть price guardrail и проверка карантина.
- Остатки обновляет только одна мастер-система.
- Заказы синхронизируются через API-уведомления + контрольный polling.
- Отмена/перенос заказов — только по правилу или вручную.
- Все ошибки пишутся с
offerId, endpoint, body, response, timestamp.
Типовые ошибки интеграции
| Ошибка | Причина | Как исправить |
|---|---|---|
420 Enhance Your Calm | больше 4 параллельных запросов или превышен ресурсный лимит | очередь, backoff, уменьшить concurrency |
UNKNOWN_CATEGORY | неверная категория | брать категорию из /v2/categories/tree |
EMPTY_MARKET_CATEGORY | не передана категория | передать листовой marketCategoryId |
UNKNOWN_PARAMETER | характеристика не относится к категории | обновить параметры через /v2/category/{categoryId}/parameters |
INVALID_UNIT_ID | неверная единица измерения | брать unitId из справочника параметра |
| Цена в карантине | резкое изменение цены | проверить цену, исправить или подтвердить |
| Товар не обновился | данные обновляются не мгновенно | ждать несколько минут и проверять повторно |
| Остаток не совпадает | SKU отличается символами или ведущим нулём | хранить SKU строкой, не числом |
| API отключён | apiAvailability не AVAILABLE | включить API в кабинете или проверить договор |
Какой minimum viable backend нужен
Для маленького каталога можно начать с n8n + Google Sheets. Для production лучше иметь базу. Минимальные таблицы:
CREATE TABLE ym_products (
offer_id TEXT PRIMARY KEY,
business_id BIGINT NOT NULL,
campaign_id BIGINT,
market_category_id BIGINT,
market_sku BIGINT,
title TEXT,
status TEXT,
last_catalog_sync_at TIMESTAMP,
last_error TEXT
);
CREATE TABLE ym_prices (
offer_id TEXT PRIMARY KEY,
price NUMERIC,
discount_base NUMERIC,
purchase_price NUMERIC,
margin NUMERIC,
quarantine_status TEXT,
updated_at TIMESTAMP
);
CREATE TABLE ym_stocks (
offer_id TEXT,
campaign_id BIGINT,
stock INTEGER,
source TEXT,
updated_at TIMESTAMP,
PRIMARY KEY (offer_id, campaign_id)
);
CREATE TABLE ym_api_logs (
id BIGSERIAL PRIMARY KEY,
endpoint TEXT,
offer_id TEXT,
status_code INTEGER,
request_body JSONB,
response_body JSONB,
created_at TIMESTAMP DEFAULT now()
);
FAQ
Можно ли через API полностью автоматизировать Яндекс Маркет?
Да, большую часть рутины можно автоматизировать: товары, цены, остатки, заказы, FBS-документы, отзывы, вопросы, чаты и отчёты. Но цены, отмены, возвраты и спорные отзывы лучше оставлять с ручным контролем или строгими правилами.
Чем отличается offer-mappings/update от offer-cards/update?
offer-mappings/update добавляет и обновляет товар в каталоге: название, описание, фото, категория, базовые характеристики и часть цен. offer-cards/update редактирует характеристики, специфичные для категории.
Почему ошибка 420, а не 429?
Яндекс Маркет использует HTTP 420 Enhance Your Calm при превышении лимитов. Для интеграции это сигнал поставить запрос в очередь и повторить позже.
Какой размер батча лучше использовать?
Для товаров — 50–100 позиций. Для цен — 100–300. Для остатков — 500–1000. Формальные лимиты могут быть выше, но маленькие батчи проще логировать, ретраить и валидировать.
Можно ли использовать n8n?
Да, для MVP и средних объёмов. Но нужен rate limiter, батчинг, лог ошибок, credentials и контроль повторов. Для больших объёмов лучше вынести очередь и логику лимитов в backend.
Источники
- API Яндекс Маркета для продавцов — partner-api/doc
- Авторизация API-Key — concepts/authorization
- Ограничения запросов — concepts/limits
- Дерево категорий — getCategoriesTree
- Характеристики категории — getCategoryContentParameters
- Добавление товаров — updateOfferMappings
- Категорийные характеристики — updateOfferContent
- Цены для всех магазинов — updateBusinessPrices
- Цены в конкретном магазине — updatePrices
- Цены и карантин — assortment-change-prices
- Передача остатков — updateStocks
- Заказы — getOrders
- API-уведомления — push-notifications