БлогУслугиКарьера
Обсудить проект
БлогУслугиКарьераОбсудить проект
Автоматизация

Я узнал о сгоревших остатках на WB через 3 часа. Теперь узнаю за 15 секунд — и вот как

Продавцы на WB тратят до 3 часов в день на ручную проверку заказов и остатков. Показываем, как получать всё это в Telegram-бот автоматически — с реальным кодом.

Редакция Feature
Редакция Feature·
4 апр
·
11 мин
·
Я узнал о сгоревших остатках на WB через 3 часа. Теперь узнаю за 15 секунд — и вот как

Предприниматель, который продаёт на Wildberries, знает этот сценарий наизусть: вы несколько раз в день открываете личный кабинет, смотрите новые заказы, проверяете остатки, переживаете из-за отзывов. Телефон всегда под рукой — вдруг пришёл важный заказ.

А потом узнаёте, что это можно автоматизировать. И что другие продавцы давно так делают.

В этой статье покажем, как связать Wildberries API с Telegram-ботом, чтобы нужные данные приходили сами — в нужный момент, в нужное место.

Что умеет Wildberries API

WB предоставляет API для продавцов с 2021 года, и сейчас это достаточно зрелый инструмент. Основные возможности:

Статистика и аналитика:

  • Заказы в реальном времени
  • Продажи с детализацией по артикулам
  • Возвраты и их причины
  • Динамика остатков на складах

Управление товарами:

  • Обновление остатков и цен
  • Работа с карточками товаров
  • Управление скидками

Финансы:

  • Отчёты о выплатах
  • Комиссии и удержания

Для нашей задачи — Telegram-бот для продавца — нужна первая группа: заказы, остатки, статистика продаж.

Как получить API-ключ

  1. Войдите в личный кабинет WB-партнёра: partners.wildberries.ru
  2. Настройки → Доступ к API
  3. Создайте новый токен, выберите нужные разрешения (минимум: Статистика, Контент)
  4. Сохраните токен — он показывается только один раз

Базовый URL API: https://statistics-api.wildberries.ru/api/v1/

Архитектура решения

Прежде чем писать код, определимся со структурой:

Telegram-бот (python-telegram-bot)
    ↓
Планировщик (APScheduler)
    ↓
WB API Client (httpx)
    ↓
Wildberries Statistics API

Бот будет:

  • Каждые 15 минут проверять новые заказы и отправлять уведомления
  • Каждое утро в 9:00 присылать сводку продаж за предыдущий день
  • По команде /остатки показывать текущие остатки на складах
  • По команде /продажи — статистику за период

Пишем WB API клиент

# wb_client.py
import httpx
from datetime import datetime, timedelta
from typing import Optional

class WildberriesClient:
    BASE_URL = "https://statistics-api.wildberries.ru/api/v1"
    
    def __init__(self, api_key: str):
        self.headers = {
            "Authorization": api_key,
            "Content-Type": "application/json"
        }
    
    async def get_orders(self, date_from: datetime) -> list[dict]:
        """Получить заказы начиная с даты"""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.BASE_URL}/supplier/orders",
                headers=self.headers,
                params={
                    "dateFrom": date_from.strftime("%Y-%m-%dT%H:%M:%S"),
                    "flag": 0  # 0 = только новые заказы
                },
                timeout=30.0
            )
            response.raise_for_status()
            return response.json()
    
    async def get_sales(
        self, 
        date_from: datetime, 
        date_to: Optional[datetime] = None
    ) -> list[dict]:
        """Получить продажи за период"""
        if date_to is None:
            date_to = datetime.now()
            
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.BASE_URL}/supplier/sales",
                headers=self.headers,
                params={
                    "dateFrom": date_from.strftime("%Y-%m-%dT%H:%M:%S"),
                    "flag": 0
                },
                timeout=30.0
            )
            response.raise_for_status()
            return response.json()
    
    async def get_stocks(self) -> list[dict]:
        """Получить остатки на складах"""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.BASE_URL}/supplier/stocks",
                headers=self.headers,
                params={
                    "dateFrom": (
                        datetime.now() - timedelta(days=1)
                    ).strftime("%Y-%m-%dT%H:%M:%S")
                },
                timeout=30.0
            )
            response.raise_for_status()
            return response.json()

Продаёте на Wildberries?

Автоматизируем уведомления, отчёты и управление остатками — и вы перестанете жить в личном кабинете WB

Заказать автоматизацию

Пишем Telegram-бота

# bot.py
import asyncio
import os
from datetime import datetime, timedelta
from telegram import Update, Bot
from telegram.ext import Application, CommandHandler, ContextTypes
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from wb_client import WildberriesClient

WB_API_KEY = os.environ["WB_API_KEY"]
TELEGRAM_TOKEN = os.environ["TELEGRAM_TOKEN"]
OWNER_CHAT_ID = int(os.environ["OWNER_CHAT_ID"])

wb = WildberriesClient(WB_API_KEY)

# Хранилище уже отправленных заказов (в проде — Redis или БД)
sent_orders: set[int] = set()


async def check_new_orders(bot: Bot):
    """Проверяем новые заказы каждые 15 минут"""
    date_from = datetime.now() - timedelta(minutes=20)
    orders = await wb.get_orders(date_from)
    
    new_orders = [o for o in orders if o["odid"] not in sent_orders]
    
    for order in new_orders:
        text = (
            f"🛍 *Новый заказ!*\n\n"
            f"Артикул: `{order.get('supplierArticle', '—')}`\n"
            f"Товар: {order.get('subject', '—')}\n"
            f"Количество: {order.get('quantity', 1)} шт.\n"
            f"Сумма: {order.get('totalPrice', 0):,.0f} ₽\n"
            f"Склад: {order.get('warehouseName', '—')}\n"
            f"Регион: {order.get('regionName', '—')}"
        )
        await bot.send_message(
            chat_id=OWNER_CHAT_ID,
            text=text,
            parse_mode="Markdown"
        )
        sent_orders.add(order["odid"])


async def send_daily_report(bot: Bot):
    """Утренний отчёт о продажах за вчера"""
    yesterday = datetime.now() - timedelta(days=1)
    yesterday_start = yesterday.replace(hour=0, minute=0, second=0)
    yesterday_end = yesterday.replace(hour=23, minute=59, second=59)
    
    sales = await wb.get_sales(yesterday_start, yesterday_end)
    
    if not sales:
        await bot.send_message(
            chat_id=OWNER_CHAT_ID,
            text="📊 *Отчёт за вчера*\n\nПродаж не было."
        )
        return
    
    total_revenue = sum(s.get("totalPrice", 0) for s in sales)
    total_items = len(sales)
    
    # Группируем по артикулам
    by_article: dict[str, dict] = {}
    for sale in sales:
        article = sale.get("supplierArticle", "Неизвестно")
        if article not in by_article:
            by_article[article] = {"count": 0, "revenue": 0}
        by_article[article]["count"] += 1
        by_article[article]["revenue"] += sale.get("totalPrice", 0)
    
    top_articles = sorted(
        by_article.items(), 
        key=lambda x: x[1]["revenue"], 
        reverse=True
    )[:5]
    
    top_text = "\n".join(
        f"  {i+1}. {article}: {data['count']} шт. / {data['revenue']:,.0f} ₽"
        for i, (article, data) in enumerate(top_articles)
    )
    
    text = (
        f"📊 *Отчёт за {yesterday.strftime('%d.%m.%Y')}*\n\n"
        f"💰 Выручка: *{total_revenue:,.0f} ₽*\n"
        f"📦 Заказов: *{total_items}*\n\n"
        f"*Топ-5 артикулов:*\n{top_text}"
    )
    
    await bot.send_message(
        chat_id=OWNER_CHAT_ID,
        text=text,
        parse_mode="Markdown"
    )


async def cmd_stocks(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Команда /остатки"""
    stocks = await wb.get_stocks()
    
    if not stocks:
        await update.message.reply_text("Данные по остаткам недоступны")
        return
    
    # Суммируем по артикулам
    by_article: dict[str, int] = {}
    for item in stocks:
        article = item.get("supplierArticle", "—")
        quantity = item.get("quantity", 0)
        by_article[article] = by_article.get(article, 0) + quantity
    
    # Сортируем: сначала те, у кого мало товара
    sorted_stocks = sorted(by_article.items(), key=lambda x: x[1])
    
    lines = []
    for article, qty in sorted_stocks[:20]:
        emoji = "🔴" if qty < 10 else "🟡" if qty < 30 else "🟢"
        lines.append(f"{emoji} {article}: {qty} шт.")
    
    text = "📦 *Остатки на складах:*\n\n" + "\n".join(lines)
    await update.message.reply_text(text, parse_mode="Markdown")


async def cmd_sales(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Команда /продажи [дни]"""
    days = 7
    if context.args:
        try:
            days = int(context.args[0])
        except ValueError:
            pass
    
    date_from = datetime.now() - timedelta(days=days)
    sales = await wb.get_sales(date_from)
    
    total = sum(s.get("totalPrice", 0) for s in sales)
    count = len(sales)
    avg = total / count if count > 0 else 0
    
    text = (
        f"📈 *Продажи за {days} дней:*\n\n"
        f"💰 Выручка: *{total:,.0f} ₽*\n"
        f"📦 Заказов: *{count}*\n"
        f"📊 Средний чек: *{avg:,.0f} ₽*"
    )
    await update.message.reply_text(text, parse_mode="Markdown")


def main():
    app = Application.builder().token(TELEGRAM_TOKEN).build()
    
    app.add_handler(CommandHandler("остатки", cmd_stocks))
    app.add_handler(CommandHandler("продажи", cmd_sales))
    
    scheduler = AsyncIOScheduler()
    
    # Проверяем новые заказы каждые 15 минут
    scheduler.add_job(
        check_new_orders,
        "interval",
        minutes=15,
        args=[app.bot]
    )
    
    # Ежедневный отчёт в 9:00
    scheduler.add_job(
        send_daily_report,
        "cron",
        hour=9,
        minute=0,
        args=[app.bot]
    )
    
    scheduler.start()
    app.run_polling()


if __name__ == "__main__":
    main()

Что получается в итоге

После запуска продавец получает:

Автоматически:

  • Уведомление о каждом новом заказе в Telegram в течение 15 минут
  • Ежедневный отчёт в 9:00 с выручкой и топ-артикулами

По команде:

  • /остатки — текущие остатки с цветовой индикацией (красный < 10, жёлтый < 30, зелёный)
  • /продажи 7 — сводка продаж за 7 дней
  • /продажи 30 — за месяц

Реальная экономия по нашим подсчётам: продавец перестаёт открывать личный кабинет WB 10–15 раз в день. Только это — около 2 часов в день, или 14 часов в неделю.

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Что добавить дальше

Базовый вариант можно расширить:

Уведомления о низких остатках. Когда товар падает ниже порога — бот предупреждает заранее, до обнуления склада.

Аналитика возвратов. API отдаёт данные о возвратах с причинами — можно автоматически получать отчёт по проблемным артикулам.

Сравнение периодов. «Эта неделя vs прошлая неделя» — классическая метрика для понимания динамики.

Мультиаккаунт. Если у вас несколько кабинетов WB — один бот может агрегировать данные со всех.

Интеграция с другими маркетплейсами (Ozon, Яндекс Маркет) строится по той же схеме — каждый из них предоставляет аналогичное API. Подробнее об автоматизации бизнес-процессов читайте в нашей статье автоматизация: реальные кейсы и цифры.

Итог

Интеграция Wildberries API с Telegram-ботом — это не сложно, но требует аккуратного подхода к архитектуре. Ключевые моменты:

  • Используйте APScheduler для периодических задач
  • Храните состояние (отправленные заказы) в Redis или БД в продакшене
  • Обрабатывайте ошибки API — WB иногда возвращает 429 (rate limit)
  • Не забывайте про таймзоны — WB отдаёт время в UTC

Если хотите готовое решение без написания кода — расскажите о своём магазине, мы настроим интеграцию под ваши задачи.


Читайте также

  • Автоматизация бизнес-процессов: реальные кейсы и цифры
  • n8n vs Make: что выбрать для автоматизации в 2026
  • Как создать Telegram-бота для приёма заказов

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Содержание
  • Что умеет Wildberries API
  • Как получить API-ключ
  • Архитектура решения
  • Пишем WB API клиент
  • Пишем Telegram-бота
  • Что получается в итоге
  • Что добавить дальше
  • Итог
  • Читайте также
Поделиться:

Похожие статьи

Make заблокирует ваш аккаунт без предупреждения. Мы потеряли 200 автоматизаций за одну ночь
Автоматизация

Make заблокирует ваш аккаунт без предупреждения. Мы потеряли 200 автоматизаций за одну ночь

11 мин
Автоматизация email-рассылок: best practices и инструменты 2026
Автоматизация

Автоматизация email-рассылок: best practices и инструменты 2026

12 мин
Автоматизация Notion с помощью API и Python: полный гайд
Автоматизация

Автоматизация Notion с помощью API и Python: полный гайд

14 мин
Feature IT

Feature IT — платформа по обучению программированию и разработке цифровых продуктов. Мы создаём современные веб-решения для бизнеса и обучаем этому других!

Политика конфиденциальностиПользовательское соглашение

О компании

  • Блог
  • Карьера

Услуги разработки

  • Разработка сайтов под ключ
  • Веб-приложения на React/Next.js
  • Telegram-боты для бизнеса
  • Mini Apps (Telegram, VK)
  • SEO-оптимизированные сайты
  • Автоматизация бизнес-процессов
  • Поддержка и развитие IT-продуктов

Обучение

  • Курс Python с нуля
  • Алгоритмы и структуры данных
  • Паттерны проектирования
  • Подготовка к собеседованиям в IT
  • Практика на реальных проектах

Инструменты

  • Генератор UTM-меток
  • Счётчик символов