Предприниматель, который продаёт на Wildberries, знает этот сценарий наизусть: вы несколько раз в день открываете личный кабинет, смотрите новые заказы, проверяете остатки, переживаете из-за отзывов. Телефон всегда под рукой — вдруг пришёл важный заказ.
А потом узнаёте, что это можно автоматизировать. И что другие продавцы давно так делают.
В этой статье покажем, как связать Wildberries API с Telegram-ботом, чтобы нужные данные приходили сами — в нужный момент, в нужное место.
Что умеет Wildberries API
WB предоставляет API для продавцов с 2021 года, и сейчас это достаточно зрелый инструмент. Основные возможности:
Статистика и аналитика:
- Заказы в реальном времени
- Продажи с детализацией по артикулам
- Возвраты и их причины
- Динамика остатков на складах
Управление товарами:
- Обновление остатков и цен
- Работа с карточками товаров
- Управление скидками
Финансы:
- Отчёты о выплатах
- Комиссии и удержания
Для нашей задачи — Telegram-бот для продавца — нужна первая группа: заказы, остатки, статистика продаж.
Как получить API-ключ
- Войдите в личный кабинет WB-партнёра:
partners.wildberries.ru
- Настройки → Доступ к API
- Создайте новый токен, выберите нужные разрешения (минимум: Статистика, Контент)
- Сохраните токен — он показывается только один раз
Базовый 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()
Пишем 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
Если хотите готовое решение без написания кода — расскажите о своём магазине, мы настроим интеграцию под ваши задачи.
Читайте также