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

Я узнал о сгоревших остатках на 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-бота
  • Что получается в итоге
  • Что добавить дальше
  • Итог
  • Читайте также
Поделиться:

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

Свои вебхуки: как отдавать события партнёрам и не потерять их
Автоматизация

Свои вебхуки: как отдавать события партнёрам и не потерять их

13 мин
OAuth 2.0 для интеграций: как подключить сайт к чужому сервису
Автоматизация

OAuth 2.0 для интеграций: как подключить сайт к чужому сервису

14 мин
Настройка API на сайте: 7 ошибок, которые вылезают только в проде
Автоматизация

Настройка API на сайте: 7 ошибок, которые вылезают только в проде

13 мин
Feature IT

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

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

О компании

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

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

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

Обучение

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

Инструменты

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