Вы просыпаетесь утром и видите, что ваш товар на Ozon улетел на 100 страницу выдачи — цену сбили конкуренты за ночь. Handmade демпинг ведёт к нулевой марже и нераспроданному стоку. Нужна автоматизация: бот, который мониторит цены конкурентов, применяет гибкие стратегии и публикует коррекции через API маркетплейсов. Ниже — как мы это делаем.
Когда ручное управление не спасает: типичные проблемы продавца
Конкуренты меняют цены несколько раз в день — уследить самому невозможно: либо упустишь профит, либо продаёшь в минус. Многие стратегии в Excel не работают, потому что время отклика измеряется минутами, а не часами. Нет защиты от ценовых войн — два селлера гоняют цену до нуля, а третий выбрасывает товар по себестоимости. Сложно тестировать гипотезы — правило «снизить на 5%, если конкурент снизил» без репрайсинг-бота превращается в аналоговый ад.
Правильно настроенный repricing — это стабильный рост конверсии при сохранении маржинальности. Ошибка в одном коэффициенте — и вы в минусе. Поэтому бот должен уметь: соблюдать маржинальный флор, анализировать позицию в Buy Box, принудительно приостанавливаться при подозрении на ценовую войну.
Как мы проектируем репрайсинг-систему
Стек привычный: PHP 8.3 + Laravel 11 для бэкенда, PostgreSQL для хранения правил, логов и статистики. Движок репрайсинга — набор классов с чёткими ответственностями: правило (RepricingRule), движок (RepricingEngine), детектор ценовой войны (PriceWarDetector) и публикатор (OzonPricePublisher / WbPricePublisher).
Схема данных: правила репрайсинга
CREATE TABLE repricing_rules ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, marketplace VARCHAR(50) NOT NULL, -- 'ozon', 'wildberries', 'yandex_market' scope_type VARCHAR(20) NOT NULL, -- 'global', 'category', 'product' scope_id BIGINT, strategy VARCHAR(30) NOT NULL, -- 'min_price', 'buy_box', 'rule_based' min_price_mode VARCHAR(20) DEFAULT 'margin_floor', min_price_value NUMERIC(12,2), min_margin_pct NUMERIC(5,2) DEFAULT 10, max_price NUMERIC(12,2), step_pct NUMERIC(5,2) DEFAULT 1.0, step_abs NUMERIC(10,2), cooldown_minutes INT DEFAULT 60, is_active BOOLEAN DEFAULT TRUE ); CREATE TABLE repricing_log ( id BIGSERIAL PRIMARY KEY, product_id BIGINT REFERENCES products(id), marketplace VARCHAR(50), old_price NUMERIC(12,2), new_price NUMERIC(12,2), reason TEXT, rule_id BIGINT REFERENCES repricing_rules(id), triggered_at TIMESTAMP DEFAULT NOW() ); Такая структура позволяет гибко настраивать стратегии: на уровне всего магазина (global), для категории или для конкретного товара. В правилах обязательны ограничители — минимальная цена (fixed или % от себестоимости), максимальная, шаг изменения и кулдаун между публикациями. Лог — не только для отладки, но и для аналитики.
Как получать цены конкурентов: Ozon и Wildberries
Для Ozon используем эндпоинт /v1/product/info/competitor-price. Он возвращает цены конкурентов в Buy Box вместе с их рейтингом. Пример на PHP:
class OzonCompetitorPriceClient { public function getCompetitorPrices(string $offerId): array { $response = Http::withHeaders([ 'Client-Id' => $this->clientId, 'Api-Key' => $this->apiKey, ])->post('https://api-seller.ozon.ru/v1/product/info/competitor-price', [ 'offer_id' => $offerId, ]); return $response->json('result', []); } } Wildberries — карточка товара и парсинг card.wb.ru (в некоторых случаях API v2). Получаем массив sizes, где указаны цены для разных размеров, включая цену конкурента.
Движок репрайсинга: как принимается решение
class RepricingEngine { public function calculateNewPrice( Product $product, string $marketplace, RepricingRule $rule, ): ?PriceDecision { $competitorData = $this->getCompetitorData($product, $marketplace); $costPrice = $product->cost_price ?? 0; $currentPrice = $this->getCurrentMarketplacePrice($product, $marketplace); $decision = match ($rule->strategy) { 'min_price' => $this->strategyMinPrice($currentPrice, $competitorData, $rule, $costPrice), 'buy_box' => $this->strategyBuyBox($currentPrice, $competitorData, $rule, $costPrice), 'rule_based' => $this->strategyRuleBased($currentPrice, $competitorData, $rule, $costPrice), default => null, }; if (!$decision) return null; // Проверка cooldown $lastChange = RepricingLog::where('product_id', $product->id) ->where('marketplace', $marketplace) ->where('triggered_at', '>=', now()->subMinutes($rule->cooldown_minutes)) ->exists(); if ($lastChange) return null; return $decision; } private function strategyMinPrice( float $current, array $competitors, RepricingRule $rule, float $costPrice ): ?PriceDecision { $competitorMin = collect($competitors)->min('price'); if (!$competitorMin) return null; $floor = $this->calculateFloor($rule, $costPrice); if ($competitorMin < $current) { $newPrice = max($competitorMin, $floor); if ($newPrice >= $current) return null; return new PriceDecision( newPrice: $newPrice, reason: "Конкурент снизил цену до {$competitorMin}", ); } if ($competitorMin > $current && $rule->max_price && $current < $rule->max_price) { $newPrice = min($competitorMin - 1, $rule->max_price); return new PriceDecision( newPrice: $newPrice, reason: "Конкурент поднял цену до {$competitorMin}", ); } return null; } private function calculateFloor(RepricingRule $rule, float $costPrice): float { if ($rule->min_price_mode === 'fixed' && $rule->min_price_value) { return $rule->min_price_value; } if ($rule->min_margin_pct && $costPrice > 0) { return $costPrice * (1 + $rule->min_margin_pct / 100); } return 0; } } Ключевое — стратегия Min Price. Минимальная цена конкурента сравнивается с текущей: если конкурент дешевле — снижаем до его цены (но не ниже вычисленного floor); если конкурент дороже и есть потолок — поднимаем. Кулдаун предотвращает частые скачки.
Как устроена защита от ценовых войн?
Ценовая война — когда два селлера бесконечно снижают цены друг за другом. Наш детектор:
class PriceWarDetector { public function isWarring(int $productId, string $marketplace): bool { $changes = RepricingLog::where('product_id', $productId) ->where('marketplace', $marketplace) ->where('triggered_at', '>=', now()->subDay()) ->count(); if ($changes >= 5) { Cache::put("repricing.paused.{$productId}.{$marketplace}", true, now()->addHours(6)); Notification::send($this->admins, new PriceWarAlert($productId, $marketplace)); return true; } return false; } } Порог (5 изменений за 24 часа) настраивается под категорию товара. Пока бот заморожен, можно вручную разобраться или поднять цену.
Мониторинг и отчёты: SQL для аналитики
SELECT p.name, rl.marketplace, COUNT(*) AS changes_count, MIN(rl.new_price) AS min_price_today, MAX(rl.new_price) AS max_price_today, ROUND(AVG(rl.new_price), 2) AS avg_price_today FROM repricing_log rl JOIN products p ON p.id = rl.product_id WHERE rl.triggered_at >= NOW() - INTERVAL '24 hours' GROUP BY p.name, rl.marketplace ORDER BY changes_count DESC; Такой запрос выдаёт картину за день: какие товары менялись часто, в каком диапазоне цен. Можно добавить сегментацию по стратегии или категории.
Расписание задач
$schedule->job(new RunRepricingJob)->everyThirtyMinutes(); $schedule->job(new ResetRepricingCountersJob)->dailyAt('03:00'); Каждые 30 минут — запуск репрайсинга для активных правил. Ночью — сброс счётчиков. Время запуска можно менять под пиковые нагрузки конкретного маркетплейса.
Сравнение стратегий репрайсинга
| Стратегия | Описание | Когда использовать |
|---|---|---|
| Min Price | Удерживать цену на уровне минимальной среди конкурентов | Высокая конкуренция, товары с низкой дифференциацией |
| Buy Box | Ориентироваться на выигрыш в корзине (цена + рейтинг) | Товары, где Buy Box даёт 80% продаж |
| Rule-Based | Гибкие условия (например, снижать на 5% при снижении конкурента) | Сложные сценарии с сезонностью или акциями |
| Margin Floor | Защита минимальной маржи (цена не ниже себестоимости + процент) | Товары с низкой маржой |
Что входит в разработку репрайсинг-бота
Мы реализуем проект под ключ за 6–8 рабочих дней. В объём работ входит:
- Проектирование схемы данных и движка базовых стратегий (2 дня)
- Интеграция с Ozon API (цены конкурентов + публикация) (1–2 дня)
- Интеграция с Wildberries API (+1 день)
- Механизм PriceWarDetector с cooldown и алертами (1 день)
- Интерфейс управления правилами и лог изменений (1–2 дня)
- Полная документация по API (схемы запросов/ответов), инструкция по настройке правил, обучение вашей команды базовому администрированию, поддержка при запуске.
Мы гарантируем корректную интеграцию с официальными API — наш опыт включает более 50 проектов по автоматизации маркетплейсов. Стоимость фиксируется в договоре и не меняется в процессе.
Чек-лист: типичные ошибки при внедрении репрайсинга
- Нет кулдауна — цены меняются каждые 5 минут, Ozon блокирует API.
- Не указан min_price — уходите в минус по марже.
- Забыли про сторнирование — если цена ниже себестоимости, бот должен сразу остановить правку.
- Не мониторите ошибки — silent fail при публикации цены приводит к тому, что товар стоит по старой цене.
Свяжитесь с нами, чтобы обсудить ваш сценарий — мы пришлём примерное ТЗ и ответим на вопросы в течение дня.







