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

Вебхуки: уведомления о статусах заявок

Вебхуки — это уведомления, которые МПФИТ сам отправляет в вашу систему, когда с заявкой что-то происходит. Не нужно опрашивать наш API по кругу и ждать, пока изменения обнаружатся: как только заявка создана или у неё сменился статус, мы делаем запрос на ваш адрес.

Вебхуки пригодятся, если вы уже создаёте заявки в МПФИТ из своей учётной системы — МойСклад, Битрикс24, 1С или собственной разработки — и хотите видеть в ней актуальные статусы.

Настройка вебхуков — работа для разработчика: нужен адрес, который принимает запросы, и код, который их обрабатывает.

Событие Когда приходит
`arrival.created` создана заявка на приёмку
`arrival.status_changed` у заявки на приёмку сменился статус
`shipment.created` создана заявка на отгрузку или заказ
`shipment.status_changed` у заявки на отгрузку или заказа сменился статус
`ping` проверочное сообщение, отправляем по запросу

Вы подписываетесь на все события или только на нужные.

Заявки на приёмку и отгрузку по ФБО приходят сразу, в момент события.

Заказы ФБС приходят пачкой, раз в полчаса. Их слишком много для мгновенной отправки: за это время статус заказа успевает смениться несколько раз, поэтому вы получите одно уведомление с последним статусом на момент отправки. Промежуточные состояния в него не попадут.

  1. Подготовьте на своей стороне адрес, который будет принимать запросы. Требования к нему — в разделе ниже.
  2. Напишите в поддержку МПФИТ: укажите адрес и события, на которые подписываетесь.
  3. В ответ вы получите секрет — строку, которой подписываются все сообщения. Храните её как пароль: не публикуйте в репозитории и не передавайте в переписке третьим лицам.
  4. Попросите отправить проверочное сообщение ping и убедитесь, что оно дошло и ваш обработчик ответил успешно.

Если нужно сузить поток — например получать смену статуса приёмки только на «завершена» — скажите об этом при подключении: подписку можно ограничить конкретными статусами.

Мы отправляем POST с телом в формате JSON:

{
"id": "evt_0198c202-c4ca-7791-9216-4b727c947175",
"type": "shipment.status_changed",
"version": 1,
"created_at": "2026-08-03T12:34:56+03:00",
"data": {
"object_type": "shipment",
"event": "status_changed",
"object_id": 845213,
"number": "WMS-845213",
"seller_company_id": 11986,
"ff_company_id": 1772,
"direction": "external",
"marketplace_id": 1,
"source": "api",
"status": "SHIPPED",
"previous_status": "READY_TO_SHIP"
}
}

Общие поля любого сообщения:

Поле Значение
`id` уникальный номер события. По нему отсеивайте повторы
`type` тип события из таблицы выше
`version` версия формата
`created_at` момент события
`data` подробности события

Уведомление о приёмке устроено так же:

{
"id": "evt_0198c202-c4d5-7cc9-9a4c-8dcf4400b74e",
"type": "arrival.status_changed",
"version": 1,
"created_at": "2026-08-03T09:15:02+03:00",
"data": {
"object_type": "arrival",
"event": "status_changed",
"object_id": 51204,
"seller_company_id": 11986,
"ff_company_id": 1772,
"source": "api",
"status": "COMPLETED",
"previous_status": "NEW"
}
}
Поле Есть у Значение
`object_type` всех `shipment` — отгрузка или заказ, `arrival` — приёмка
`event` всех `created` — заявка создана, `status_changed` — сменился статус
`object_id` всех номер заявки в МПФИТ. По нему запрашивайте подробности через API
`seller_company_id` всех компания-продавец, которой адресовано событие
`ff_company_id` всех фулфилмент, который обслуживает заявку
`source` всех `api` — заявка создана через API, `internal` — создана в интерфейсе МПФИТ или пришла с маркетплейса
`status` всех текущий статус
`previous_status` всех статус до изменения. У события создания — `null`
`number` отгрузки номер заказа
`direction` отгрузки `fbs` — заказ отгружается по ФБС, `external` — поставка ФБО и другие типы
`marketplace_id` отгрузки маркетплейс заказа

В уведомлении намеренно нет позиций, товаров и остатков: состав заявки запрашивайте через наш API по object_id — там он всегда актуален. Ссылка на документацию — mpfit.ru/api.

Одна заявка на приёмку может содержать товары нескольких продавцов. Каждому продавцу уходит своё уведомление, в котором указан только его seller_company_id.

Статусы отгрузок и заказов:

Значение Что означает
`NEW` новый
`ALL_PRODUCTS_RESERVED` товар забронирован
`PROCESSING` комплектация
`READY_TO_SHIP` готов к отгрузке
`DELIVERING` в доставке
`COMPLETED` выполнен
`REJECT` отказ клиента
`CANCEL` отмена поставщиком
`SHIPPED` отгружен
`ARCHIVE` архив

Статусы приёмки:

Значение Что означает
`NEW` заявка создана, товар ещё принимается
`COMPLETED` приёмка завершена
`ARCHIVED` заявка закрыта без приёмки: груз или товар не прибыл, либо заявка отправлена в архив

Внутренних статусов приёмки больше, но наружу они сведены к этим трём. Переходы, которые не меняют статус из таблицы, мы не отправляем — лишних уведомлений не будет.

Каждый запрос содержит три заголовка:

X-MPFIT-Event-Id: evt_0198c202-c4ca-7791-9216-4b727c947175
X-MPFIT-Event-Type: shipment.status_changed
X-MPFIT-Signature: t=1754212496,v1=9f2c1d...

t — время отправки, v1 — подпись: HMAC-SHA256 от строки «t.тело запроса» на вашем секрете.

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

  1. возьмите сырое тело запроса, до разбора JSON;
  2. посчитайте HMAC-SHA256(секрет, t + "." + тело);
  3. сравните с v1 функцией сравнения в постоянном времени;
  4. отбросьте запрос, если t старше 5 минут.

Пример на PHP:

[$t, $v1] = sscanf($_SERVER['HTTP_X_MPFIT_SIGNATURE'], 't=%d,v1=%s');
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $t . '.' . $body, $secret);
if (!hash_equals($expected, $v1) || abs(time() - $t) > 300) {
http_response_code(403);
exit;
}

Пример на Python:

import hmac, hashlib, time
raw = request.get_data()
parts = dict(p.split("=", 1) for p in request.headers["X-MPFIT-Signature"].split(","))
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, parts["v1"]) or abs(time.time() - int(parts["t"])) > 300:
abort(403)

Ответьте любым кодом 2xx — этого достаточно, тело ответа мы не читаем. На ответ есть 5 секунд, поэтому обработку выносите в свою очередь: приняли, поставили в очередь, ответили.

Что происходит при других ответах:

Ваш ответ Что делаем
`2xx` считаем доставленным
`429`, `408`, `5xx`, таймаут повторяем: через 1 минуту, 5 минут, полчаса, 2 часа, 6 часов, 12 часов. Всего 7 попыток
остальные `4xx`, редиректы `3xx` считаем ошибкой настройки и не повторяем

Если приёмник перестал отвечать, мы на время приостановим отправку на него и продолжим, когда он оживёт. Накопившиеся уведомления при этом не теряются, пока не исчерпаны попытки.

Повторы возможны. Если ваш ответ до нас не дошёл, мы отправим уведомление ещё раз. Сохраняйте id события и игнорируйте те, что уже обработаны.

Порядок не гарантирован. После повторных попыток более раннее событие может прийти позже более позднего. Считайте уведомление сигналом «сходи проверь», а действительное состояние заявки берите из API по object_id.

Статусы могут перескакивать. Особенно у ФБС-заказов, где за полчаса заказ проходит несколько состояний. Не стройте логику на том, что вы увидите каждый промежуточный статус.

Незнакомые типы событий не должны ломать обработчик. Мы добавляем события, и приёмник должен спокойно пропускать то, чего пока не понимает.

  • Только https:// и стандартный порт 443.
  • Адрес должен быть доступен из интернета — на локальные и внутренние адреса сети мы не отправляем.
  • Без логина и пароля в самом адресе.
  • Без редиректов: отвечайте на указанный адрес сами, а не перенаправляйте запрос.
  • Сертификат должен быть действующим.

Можно ли получать уведомления на несколько адресов? Да, подписок может быть несколько — например рабочая и тестовая.

Придут ли уведомления по заявкам, созданным не через API? Да. Заявки, созданные в интерфейсе МПФИТ или пришедшие с маркетплейса, тоже попадают в поток — отличить их можно по полю source.

Что делать, если уведомления перестали приходить? Проверьте, что ваш адрес отвечает 2xx и укладывается в 5 секунд, а затем напишите в поддержку — мы посмотрим журнал доставки по вашей подписке.

Как сменить адрес или список событий? Напишите в поддержку, подписку изменят.