Перейти к основному содержимому

Webhooks (Push Notifications) — Ozon Seller API

Overview

Ozon Seller API использует механизм push-уведомлений (webhooks) для отправки реальных событий на ваш сервер. Это позволяет вашей системе мгновенно реагировать на изменения в заказах, товарах, сообщениях и других сущностях маркетплейса.

Официальная документация: https://docs.ozon.ru/api/seller/en/#tag/push_intro


Важные термины

  • Push-уведомление — HTTP-запрос, который Ozon отправляет на ваш URL при наступлении события
  • MessageType — тип уведомления (константа, идентифицирующая событие)
  • Payload — JSON-тело уведомления с данными события

Типы уведомлений (Message Types)

Ozon Seller API поддерживает 13 типов push-уведомлений:

1. TYPE_PING

Проверка соединения. Отправляется при первоначальном подключении и периодически для проверки доступности вашего сервера.

2. TYPE_NEW_POSTING

Новое отправление (заказ). Уведомление о создании нового заказа.

3. TYPE_POSTING_CANCELLED

Отмена отправления. Заказ был отменён.

4. TYPE_STATE_CHANGED

Изменение статуса отправления. Статус заказа изменился.

5. TYPE_CUTOFF_DATE_CHANGED

Изменение даты отгрузки. Дата, к которой нужно подготовить товар, изменилась.

6. TYPE_DELIVERY_DATE_CHANGED

Изменение даты доставки. Промежуток времени для доставки изменился.

7. TYPE_CREATE_OR_UPDATE_ITEM

Создание или обновление товара. Товар создан, обновлён или возникла ошибка при обработке.

8. TYPE_PRICE_INDEX_CHANGED

Изменение ценового индекса. Изменился ценовой индекс товара.

9. TYPE_STOCKS_CHANGED

Изменение остатков. Остатки товаров на складе изменились.

10. TYPE_NEW_MESSAGE

Новое сообщение в чате. Покупатель или служба поддержки отправили сообщение.

11. TYPE_UPDATE_MESSAGE

Изменение сообщения в чате. Сообщение было отредактировано.

12. TYPE_MESSAGE_READ

Прочитанное сообщение. Покупатель или служба поддержки прочитали ваше сообщение.

13. TYPE_CHAT_CLOSED

Чат закрыт. Чат с покупателем был закрыт.


Структуры payload для каждого типа

Общая структура для всех уведомлений

{
"message_type": "TYPE_..."
}

1. TYPE_PING — Проверка соединения

Запрос:

{
"message_type": "TYPE_PING",
"time": "2026-02-10T12:00:00Z"
}

Ожидаемый ответ:

{
"version": "1.0",
"name": "Ozon Seller API",
"time": "2026-02-10T12:00:00Z"
}

2. TYPE_NEW_POSTING — Новое отправление

{
"message_type": "TYPE_NEW_POSTING",
"posting_number": "12345678-0001",
"products": [
{
"sku": 123456,
"quantity": 2
}
],
"in_process_at": "2026-02-10T12:00:00Z",
"warehouse_id": 123456789,
"seller_id": 12345
}

Поля:

  • posting_number (string) — Номер отправления
  • products (array) — Массив товаров в отправлении
    • sku (int64) — SKU товара
    • quantity (int64) — Количество
  • in_process_at (datetime) — Дата и время начала обработки в UTC
  • warehouse_id (int64) — ID склада
  • seller_id (int64) — ID продавца

3. TYPE_POSTING_CANCELLED — Отмена отправления

{
"message_type": "TYPE_POSTING_CANCELLED",
"posting_number": "12345678-0001",
"products": [
{
"sku": 123456,
"quantity": 2
}
],
"old_state": "awaiting_packaging",
"new_state": "posting_canceled",
"changed_state_date": "2026-02-10T12:00:00Z",
"reason": {
"id": 1,
"message": "Покупатель отменил заказ"
},
"warehouse_id": 123456789,
"seller_id": 12345
}

Дополнительные поля:

  • old_state (string) — Предыдущий статус
  • new_state (string) — Новый статус (обычно posting_canceled)
  • changed_state_date (datetime) — Дата и время изменения статуса
  • reason (object) — Причина отмены
    • id (int64) — ID причины
    • message (string) — Описание причины

4. TYPE_STATE_CHANGED — Изменение статуса

{
"message_type": "TYPE_STATE_CHANGED",
"posting_number": "12345678-0001",
"new_state": "delivering",
"changed_state_date": "2026-02-10T12:00:00Z",
"warehouse_id": 123456789,
"seller_id": 12345
}

5. TYPE_CUTOFF_DATE_CHANGED — Изменение даты отгрузки

{
"message_type": "TYPE_CUTOFF_DATE_CHANGED",
"posting_number": "12345678-0001",
"new_cutoff_date": "2026-02-12T18:00:00Z",
"old_cutoff_date": "2026-02-11T18:00:00Z",
"warehouse_id": 123456789,
"seller_id": 12345
}

6. TYPE_DELIVERY_DATE_CHANGED — Изменение даты доставки

{
"message_type": "TYPE_DELIVERY_DATE_CHANGED",
"posting_number": "12345678-0001",
"new_delivery_date_begin": "2026-02-15T00:00:00Z",
"new_delivery_date_end": "2026-02-17T23:59:59Z",
"old_delivery_date_begin": "2026-02-14T00:00:00Z",
"old_delivery_date_end": "2026-02-16T23:59:59Z",
"warehouse_id": 123456789,
"seller_id": 12345
}

7. TYPE_CREATE_OR_UPDATE_ITEM — Создание/обновление товара

{
"message_type": "TYPE_CREATE_OR_UPDATE_ITEM",
"offer_id": "PRODUCT-123",
"product_id": 123456789,
"is_error": false,
"changed_at": "2026-02-10T12:00:00Z",
"seller_id": 12345
}

Поля:

  • offer_id (string) — Идентификатор товара в системе продавца
  • product_id (int64) — ID товара в Ozon
  • is_error (boolean) — true если при создании/обновлении возникли ошибки
  • changed_at (datetime) — Дата и время обновления

8. TYPE_PRICE_INDEX_CHANGED — Изменение ценового индекса

{
"message_type": "TYPE_PRICE_INDEX_CHANGED",
"updated_at": "2026-02-10T12:00:00Z",
"sku": 123456,
"product_id": 123456789,
"price_index": 1500,
"seller_id": 12345
}

Поля:

  • price_index (int64) — Новый ценовой индекс (в копейках)

9. TYPE_STOCKS_CHANGED — Изменение остатков

{
"message_type": "TYPE_STOCKS_CHANGED",
"items": [
{
"updated_at": "2026-02-10T12:00:00Z",
"sku": 123456,
"product_id": 123456789,
"stocks": [
{
"warehouse_id": 123456789,
"present": 100,
"reserved": 10
}
]
}
],
"seller_id": 12345
}

Поля:

  • items (array) — Массив товаров с изменившимися остатками
    • updated_at (datetime) — Дата и время обновления
    • sku (int64) — SKU товара (для FBS/rFBS)
    • product_id (int64) — ID товара
    • stocks (array) — Массив остатков по складам
      • warehouse_id (int64) — ID склада
      • present (int64) — Общее количество товара
      • reserved (int64) — Зарезервировано

10. TYPE_NEW_MESSAGE — Новое сообщение в чате

{
"message_type": "TYPE_NEW_MESSAGE",
"chat_id": "chat-12345",
"chat_type": "CUSTOMER",
"message_id": "msg-67890",
"created_at": "2026-02-10T12:00:00Z",
"user": {
"id": "user-999",
"type": "CUSTOMER"
},
"data": [
"Здравствуйте, когда будет отправка?"
],
"seller_id": 12345
}

Поля:

  • chat_id (string) — ID чата
  • chat_type (string) — Тип чата (CUSTOMER, SUPPORT)
  • message_id (string) — ID сообщения
  • created_at (datetime) — Дата создания
  • user (object) — Отправитель
    • id (string) — ID пользователя
    • type (string) — Тип (CUSTOMER, SUPPORT, SELLER)
  • data (array of strings) — Содержание сообщения в формате Markdown

11. TYPE_UPDATE_MESSAGE — Изменение сообщения

{
"message_type": "TYPE_UPDATE_MESSAGE",
"chat_id": "chat-12345",
"chat_type": "CUSTOMER",
"message_id": "msg-67890",
"created_at": "2026-02-10T12:00:00Z",
"updated_at": "2026-02-10T12:05:00Z",
"user": {
"id": "user-999",
"type": "CUSTOMER"
},
"data": [
"Здравствуйте, уточните когда будет отправка?"
],
"seller_id": 12345
}

Дополнительное поле:

  • updated_at (datetime) — Дата редактирования

12. TYPE_MESSAGE_READ — Прочитанное сообщение

{
"message_type": "TYPE_MESSAGE_READ",
"chat_id": "chat-12345",
"chat_type": "CUSTOMER",
"message_id": "msg-67890",
"created_at": "2026-02-10T12:00:00Z",
"user": {
"id": "user-999",
"type": "CUSTOMER"
},
"data": [
"Ваше сообщение"
],
"last_read_message_id": "msg-67890",
"seller_id": 12345
}

Дополнительное поле:

  • last_read_message_id (string) — ID последнего прочитанного сообщения

13. TYPE_CHAT_CLOSED — Чат закрыт

{
"message_type": "TYPE_CHAT_CLOSED",
"chat_id": "chat-12345",
"chat_type": "CUSTOMER",
"user": {
"id": "user-999",
"type": "SELLER"
},
"seller_id": 12345
}

Настройка webhook-сервера

Требования к серверу

  1. Доступность: Сервер должен быть доступен из интернета по HTTPS
  2. Порт: Любой порт (настраивается в личном кабинете Ozon)
  3. Отклик: Сервер должен отвечать HTTP 200 с телом {"result": true}
  4. Timeout: Обрабатывать запросы быстро (рекомендуется < 5 секунд)

Пример реализации на Go

package main

import (
"log"

"github.com/diphantxm/ozon-api-client/ozon/notifications"
)

func main() {
// Создаём сервер на порту 5000
port := 5000
server := notifications.NewNotificationServer(port)

// Регистрируем обработчики для каждого типа уведомлений
server.Register(notifications.NewPostingType, func(req interface{}) error {
notification := req.(*notifications.NewPosting)
log.Printf("Новое отправление: %s\n", notification.PostingNumber)
// Обработка нового заказа...
return nil
})

server.Register(notifications.PostingCancelledType, func(req interface{}) error {
notification := req.(*notifications.PostingCancelled)
log.Printf("Отправление %s отменено\n", notification.PostingNumber)
// Обработка отмены...
return nil
})

server.Register(notifications.StateChangedType, func(req interface{}) error {
notification := req.(*notifications.StateChanged)
log.Printf("Статус отправления %s изменен на %s\n",
notification.PostingNumber, notification.NewState)
// Обработка изменения статуса...
return nil
})

server.Register(notifications.NewMessageType, func(req interface{}) error {
notification := req.(*notifications.NewMessage)
log.Printf("Новое сообщение в чате %s: %v\n",
notification.ChatId, notification.Data)
// Обработка нового сообщения...
return nil
})

// Запускаем сервер
if err := server.Run(); err != nil {
log.Printf("Ошибка запуска сервера: %s", err)
}
}

Пример реализации на Python

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/', methods=['POST'])
def handle_webhook():
data = request.json
message_type = data.get('message_type')

if message_type == 'TYPE_PING':
# Проверка соединения
return jsonify({
'version': '1.0',
'name': 'Ozon Seller API',
'time': datetime.utcnow().isoformat()
})

elif message_type == 'TYPE_NEW_POSTING':
posting_number = data.get('posting_number')
products = data.get('products', [])
# Обработка нового заказа
print(f"Новое отправление: {posting_number}")
for product in products:
print(f" SKU: {product['sku']}, Кол-во: {product['quantity']}")

elif message_type == 'TYPE_POSTING_CANCELLED':
posting_number = data.get('posting_number')
reason = data.get('reason', {}).get('message', 'Неизвестно')
print(f"Отправление {posting_number} отменено: {reason}")

elif message_type == 'TYPE_NEW_MESSAGE':
chat_id = data.get('chat_id')
message_data = data.get('data', [])
print(f"Новое сообщение в чате {chat_id}: {message_data}")

# ... обработка остальных типов ...

# Всегда возвращаем успешный ответ
return jsonify({'result': True})

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')

Процесс настройки webhook-интеграции

Шаг 1: Разверните webhook-сервер

  1. Разработайте и разверните сервер для приёма webhook-уведомлений
  2. Убедитесь, что сервер доступен из интернета по HTTPS
  3. Протестируйте обработку TYPE_PING запроса

Шаг 2: Зарегистрируйте webhook в личном кабинете

Официальная документация: https://docs.ozon.ru/api/seller/en/#tag/push_intro

Процесс регистрации:

  1. Войдите в личный кабинет продавца Ozon (seller.ozon.ru)
  2. Перейдите в раздел Настройки → API (или аналогичный раздел)
  3. Найдите подраздел Push-уведомления или Webhooks
  4. Укажите URL вашего webhook-сервера
  5. Выберите типы уведомлений, которые хотите получать
  6. Сохраните настройки

Важно: Точный путь настройки может отличаться. Рекомендуется обратиться к официальной документации Ozon или поддержке.

Шаг 3: Проверьте работу webhook

  1. Ozon отправит тестовый запрос TYPE_PING на ваш URL
  2. Ваш сервер должен ответить корректной структурой с версией и временем
  3. После успешной проверки Ozon начнёт отправлять уведомления

Обработка ошибок

Структура ошибки

{
"error": {
"code": "400",
"message": "Ошибка валидации",
"details": "Поле 'posting_number' обязательно"
}
}

HTTP-коды ответов

  • 200 OK — Уведомление успешно обработано
  • 400 Bad Request — Неверный формат запроса или невалидные данные
  • 500 Internal Server Error — Внутренняя ошибка вашего сервера

Важно: Даже если ваш сервер вернёт ошибку, Ozon может повторить отправку уведомления. Рекомендуется всегда возвращать 200 с {"result": true} после успешной обработки, чтобы избежать повторов.


Рекомендации по реализации

1. Идемпотентность

Уведомления могут дублироваться. Обеспечьте идемпотентность обработки:

  • Используйте message_id или posting_number как ключ идемпотентности
  • Храните обработанные уведомления в базе данных
  • Перед обработкой проверяйте, не было ли уведомление уже обработано

2. Асинхронная обработка

Не выполняйте длительные операции синхронно:

  • Сразу верните HTTP 200
  • Поместите уведомление в очередь (RabbitMQ, Redis, Kafka)
  • Обрабатывайте в фоновых воркерах

3. Логирование

Логируйте все входящие уведомления:

  • Сохраняйте исходный JSON
  • Записывайте время получения
  • Фиксируйте результаты обработки

4. Мониторинг

Настройте мониторинг:

  • Количество полученных уведомлений по типам
  • Время обработки
  • Ошибки и исключения
  • Доступность webhook-сервера

5. Безопасность

Проверяйте входящие запросы:

  • Используйте HTTPS
  • Проверяйте IP-адреса источника (если Ozon предоставит список)
  • Валидируйте структуру JSON
  • Не доверяйте данным из уведомлений без проверки

Категории уведомлений по бизнес-процессам

Управление заказами

  • TYPE_NEW_POSTING — Новый заказ
  • TYPE_POSTING_CANCELLED — Отмена заказа
  • TYPE_STATE_CHANGED — Изменение статуса
  • TYPE_CUTOFF_DATE_CHANGED — Изменение даты отгрузки
  • TYPE_DELIVERY_DATE_CHANGED — Изменение даты доставки

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

  • TYPE_CREATE_OR_UPDATE_ITEM — Создание/обновление товара
  • TYPE_PRICE_INDEX_CHANGED — Изменение цены
  • TYPE_STOCKS_CHANGED — Изменение остатков

Коммуникации с клиентами

  • TYPE_NEW_MESSAGE — Новое сообщение
  • TYPE_UPDATE_MESSAGE — Редактирование сообщения
  • TYPE_MESSAGE_READ — Прочитанное сообщение
  • TYPE_CHAT_CLOSED — Закрытие чата

Служебные

  • TYPE_PING — Проверка соединения

Полезные ссылки

Официальная документация

Клиентские библиотеки с поддержкой webhook

Сообщество

  • Telegram канал (EN): https://t.me/s/OzonEnSellerAPI
  • GitHub Issues: Открывайте issues в репозиториях клиентских библиотек

Часто задаваемые вопросы (FAQ)

В: Ozon не отправляет уведомления на мой URL

О: Проверьте:

  1. Сервер доступен по HTTPS из интернета
  2. Корректно отвечаете на TYPE_PING (нужен JSON с version, name, time)
  3. Webhook зарегистрирован в личном кабинете Ozon
  4. Выбраны нужные типы уведомлений в настройках

В: Приходят дублирующиеся уведомления

О: Это нормально. Ozon может повторять отправку при:

  • Таймауте ответа
  • Ошибке (не 200)
  • Неполном ответе

Реализуйте идемпотентность по message_id или posting_number.

В: Какой формат времени в уведомлениях?

О: Все даты в формате ISO 8601 UTC: 2026-02-10T12:00:00Z

В: Можно ли выбрать только определённые типы уведомлений?

О: Да, в личном кабинете Ozon вы можете выбрать, какие типы уведомлений получать на ваш URL.

В: Что делать если payload не соответствует документации?

О: Структуры payload могут меняться. Ozon обычно не предупреждает об изменениях. Рекомендации:

  • Валидируйте JSON при получении
  • Логируйте неизвестные поля
  • Используйте клиентские библиотеки, которые обновляются сообществом
  • Следите за обновлениями в Telegram-канале Ozon Seller API

Пример полной интеграции

Архитектура

Ozon Platform
↓ (Webhook HTTPS)
Nginx / Load Balancer

Webhook Server (Go/Python/Node.js)
↓ (валидация, логирование)
Message Queue (RabbitMQ/Redis)

Background Workers (обработка)

Database (postgres/mysql)

Поток обработки

  1. Ozon отправляет POST на webhook URL
  2. Webhook сервер принимает JSON, парсит message_type
  3. Валидирует структуру, логирует в БД
  4. Отправляет {"result": true} (HTTP 200)
  5. Кладёт событие в очередь сообщений
  6. Фоновые воркеры обрабатывают события бизнес-логикой
  7. Результаты записываются в БД

Версия документации: 1.0 Дата обновления: 10 февраля 2026 г. Источник: GitHub diPhantxm/ozon-api-client, официальная документация Ozon