Как я вытащил из Ozon Seller API все скрытые списания за месяц - разбор кода на Python
Проблема
В июне мой знакомый селлер показал отчёт по своему магазину на Ozon. Оборот за месяц - 187 тысяч. Чистыми на руки - 62. На вопрос "куда ушли остальные 125" кабинет Ozon отвечает обобщённо: "услуги логистики и рекламы", строчкой на 90 тысяч.
Дальше - вручную. Открываешь пять разных отчётов: детализация, оспаривания, отчёт по кампании, услуги, антифрод. Сводишь в Excel. На средний магазин это 3-5 часов работы в конце месяца. У большинства селлеров, с которыми я успел поговорить, эту работу никто не делает. Просто списывают разницу на "озон такой".
Меня зацепило другое: то, что "озон такой" - это не константа. Внутри этой строчки на 90 тысяч сидит несколько типов операций, каждый из которых можно отследить и часть - прямо в моменте отключить. Автоактивированные акции. Страхование FBS. Антифрод-удержания за подозрение на самовыкупы. Штрафы за отмены. У части из них есть срок оспаривания 7 дней, и если пропустишь - деньги ушли навсегда.
Я взял Ozon Seller API и написал скрипт на Python, который тянет весь финансовый поток, категоризирует каждую операцию и в конце недели присылает в Telegram отчёт: сколько ушло на реальные утечки, а сколько на нормальные комиссии. Ниже - разбор как это сделано и на что смотреть при повторении.
Что даёт Ozon Seller API
Сначала база - на случай если кто-то читает и раньше не подключался к API Ozon.
Ozon предоставляет два API: Seller API (управление товарами, заказами, финансы) и Performance API (реклама). Нам нужен первый.
Ключ получается в личном кабинете селлера: seller.ozon.ru/app/settings/api-keys. Тип ключа - Admin read only или любой другой с правами на раздел "Финансы". Это ключ только на чтение, никакие данные им изменить нельзя. Проверка прав - там же в кабинете.
Для работы с API нужны два значения: Client-Id (число) и Api-Key (строка типа abcd-1234-efgh-...). Оба передаются в HTTP-заголовках каждого запроса.
Базовый URL всех методов: https://api-seller.ozon.ru.
Про грядущее отключение метода 6 июля 2026
Важный момент, если вы читаете это после 6 июля. До 6 июля 2026 все финансовые операции магазина можно тянуть одним методом - POST /v3/finance/transaction/list. Он возвращает список операций с полем operation_type, по которому дальше их категоризируют.
С 6 июля 2026 Ozon отключает /v3/finance/transaction/list и /v3/finance/transaction/totals.
Официальная новость: dev.ozon.ru/news/699 - их заменяют новые методы:
- POST /v1/finance/decompensation - удержания (штрафы, антифрод, промо, страхование). По сути ровно тот срез, который нам и нужен.
- POST /v1/finance/compensation - компенсации (возвраты денег селлеру).
- - POST /v1/finance/accrual/by-day - начисления по дням с полем accrual_id, которое типизирует операцию.
Новые методы структурно чище: удержания и начисления разделены на стороне Ozon, а accrual_id даёт готовый тип. Категоризатор становится проще.
В своём коде я оставил обе ветки и вынес переключение в конфиг - до 6 июля работает старый метод, после - новый.
Кусок 1: запрос финансовых операций
Пара важных нюансов, которые не сразу очевидны:
Про даты. Формат 2026-07-03T00:00:00.000Z обязателен именно с миллисекундами и суффиксом Z. Без миллисекунд - 400. Без Z - 400. Я час потратил, пока понял.
Про пагинацию. page_size максимум 1000. Если у магазина за месяц больше 1000 операций (у большинства так и есть на FBS), нужно ходить по страницам. Между запросами держу sleep(0.3) - не потому что Ozon явно тротлит, а на всякий случай, чтобы не словить 429.
Про operation_type в фильтре. Пустой массив = все типы операций. Если поставить конкретный, например ["OperationMarketplaceServiceItemDelivery"], вернутся только они. Полный список типов - в документации Ozon, их пара десятков.
Кусок 2: категоризация
Тут самое интересное. Ozon возвращает operation_type (техническое имя типа MarketplaceServiceItemAntifraud) и operation_type_name (человекочитаемое имя типа "Антифрод-удержание"). Оба поля используются для правил.
Категории, которые я в итоге вывел, глядя на реальные операции:
- sale - продажи и возвраты покупателю (не утечка)
- delivery - логистика, магистраль, обработка (норма для FBS/FBO)
- penalty - штрафы Ozon
- antifraud - антифрод-удержания
- promo - акции и скидки за счёт продавца
- ads - реклама (Трафареты, поиск, брендовая полка)
- insurance - страхование FBS
- hidden_service - прочие платные сервисы Ozon, автоактивированные
- other - не распознано, глазами
Правила категоризации - простой список пар "подстрока -> категория":
Ход простой: по каждой операции проходим по правилам, первое совпадение выигрывает. Порядок правил в списке важен - более специфичные правила выше.
Что учесть при повторении:
1. Ozon использует и латиницу и кириллицу. Одна и та же операция в старых магазинах может прийти с англоязычным operation_type_name, в новых - с русским. Правила пишу для обоих вариантов.
2. Порядок правил. Правило "delivery" должно быть НИЖЕ правил "antifraud", потому что в некоторых типах антифрода в имени встречается слово delivery (тип возврата).
3. hidden_service как ловушка. Если операция содержит слово "сервис" и не подошла ни к одной другой категории - это скорее всего платный сервис Ozon, и его стоит показать селлеру отдельно с пометкой "разобраться вручную".
Кусок 3: построение отчёта
Дальше просто. Пробегаемся по всем операциям, суммируем по категориям, отбираем топ-5 самых крупных единичных списаний.
LEAK_CATEGORIES - множество тех категорий, которые считаем утечками: {"penalty", "antifraud", "promo", "insurance", "hidden_service"}.
Что получилось
Я собрал это в Telegram-бот с APScheduler. Раз в 6 часов ходит в Ozon, кэширует свежие операции в SQLite. Раз в неделю (понедельник, 10:00 МСК) шлёт селлеру сводку.
Ответ бота выглядит так:
Пример разбивки на реальный магазин на FBS:
Итого "утечка" - 53 800 из 72 000 общих списаний. Логистика в 18 450 ₽ вынесена отдельно, это нормальная себестоимость и её отключать нельзя.
Средняя картина по рынку
Ради интереса я поднял открытые данные и статьи по штрафам и удержаниям Ozon за первое полугодие 2026 (SelSup, A3-Agency, Uniseller). Средние доли по типам "утечек" от оборота:
- Штрафы: 3-8%
- Антифрод: 2-5%
- Автоакции и промо: 5-15%
- Страхование FBS: 1-3%
Суммарно у среднего селлера 5-7% оборота уходит на автоактивированные сервисы, о которых он не помнит. У некоторых больше. На обороте в 500 тысяч в месяц это 25-35 тысяч, которые можно вернуть себе без вложений - просто отключив то, что включено по умолчанию.
Про новый API после 6 июля
Как я писал выше - старый метод отключат. Новые методы делят финансовый поток иначе:
Ключевое отличие: удержания больше не смешаны с продажами и логистикой в одной ленте. Отдельный метод под удержания. Отдельный метод под начисления, и у каждого начисления есть accrual_id, который прямо содержит тип операции (штраф, промо, страхование и т.д.). Категоризация становится не по regex, а по прямому ID.
Кому важна поддержка перехода - переписывайте до конца недели. Судя по обсуждениям в чатах разработчиков, у половины интеграций после 6 июля отвалятся отчёты, потому что все привыкли к transaction/list за три года.
Итог
Скрипт делает простую вещь: тянет то, что уже лежит в Ozon Seller API, но разложено по-другому. Никакой магии. Никакого парсинга сайта, никаких обходов лимитов, никаких серых схем.
Ценность именно в разложении: увидеть в цифрах, что "озон съел 90 тысяч" - это на самом деле 23 акции + 12 антифрод + 8 страхование + 4 штраф + 5 реклама + 18 логистики. Часть - норма. Часть - можно вернуть.
Я собрал это как pet-project под рабочим названием "Утечкометр". Сейчас в закрытой бете - беру 3-5 селлеров на бесплатный прогон, чтобы откалибровать правила категоризатора на живых данных из разных магазинов. Если интересно - пишите в личку t.me/vanya_base, пришлю ссылку на бота.
Если делаете своё - часть кода выше можно брать за основу, там ничего секретного. Единственное, что советую держать в голове: operation_type_name в API Ozon иногда меняется без объявления, поэтому категоризатор нужно периодически калибровать по свежим ответам.
Пишите в комменты, если у вас в отчёте всплывают типы операций, которых нет в моих правилах - интересно посмотреть.
P.S. Часть слов в тексте vc-редактор превратил в пустые ссылки - техническое, никуда не ведут, читайте как обычный текст.
Первые 5 обратившихся - бесплатный прогон за 24 часа.
Возьму 5 селлеров с оборотом от 100 тысяч в месяц. Подключаете API-ключ Ozon с правами только на чтение (Admin read only), в течение 24 часов присылаю персональный разбор с точными цифрами куда ушли деньги и что можно отключить.
Бесплатно, без обязательств. Взамен - обратная связь, была ли информация полезной.
Пишите в лс: t.me/vanya_base
Попробовать бота в закрытой бете: https://t.me/utechkometr_bot
UPD от 5 июля: Собрал в бот кнопку "Оспорить операцию" - при клике LLM генерирует готовый текст претензии с ID операции, суммой и юридическим обоснованием по оферте Ozon.
Скринкаст:
Автор: Иван Мирасов. Пишу серверный Python, сейчас занимаюсь автоматизациями для маркетплейс-селлеров.