Использование
Эта страница описывает, что приходит на ваш URL и как на это отвечать. Полные схемы полей по каждому событию — в OpenAPI-спецификации.
Конверт запроса
Все события приходят POST-запросом с телом в формате JSON и единым конвертом:
{
"id": "0193…uuid",
"event": "order.created",
"occurred_at": "2026-05-11T10:00:00Z",
"api_version": "1",
"data": { }
}
id— идентификатор доставки, не меняется между повторами одного события.event— имя события (см. список).occurred_at— момент события (ISO-8601, UTC).api_version— версия контракта payload.data— содержимое, специфичное для события. Схема — в OpenAPI документации.
Заголовки
| Заголовок | Значение |
|---|---|
Content-Type |
application/json |
User-Agent |
Mobius-Webhooks/1.0 |
X-Mobius-Event |
имя события |
X-Mobius-Delivery |
идентификатор доставки (одинаков для всех попыток одного события) |
X-Mobius-Timestamp |
unix-секунды момента генерации запроса |
X-Mobius-Signature |
t=<timestamp>,v1=<hex hmac_sha256(timestamp + "." + тело, секрет)> |
Проверка подписи
Подписчик обязан проверять подпись и таймстемп. Это защищает от подделки запросов и от повторной отправки старого запроса.
Алгоритм:
- Возьмите сырое тело запроса (до парсинга JSON).
- Из заголовка
X-Mobius-Signatureразберитеt(таймстемп) иv1(подпись). - Вычислите
hmac_sha256(t + "." + raw_body, секрет)своим секретом подписки. - Сравните с
v1в постоянном времени. - Отклоните запрос, если подпись не совпала или
tстарше 5 минут.
Пример на PHP:
function verifyMobiusSignature(string $rawBody, string $header, string $secret): bool
{
// header: "t=1715420400,v1=abc123…"
parse_str(str_replace(',', '&', $header), $parts);
$t = $parts['t'] ?? '';
$v1 = $parts['v1'] ?? '';
if ($t === '' || $v1 === '') {
return false;
}
// Защита от повторной отправки: не старше 5 минут.
if (abs(time() - (int) $t) > 300) {
return false;
}
$expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret);
return hash_equals($expected, $v1);
}
Пример на Node.js:
const crypto = require('crypto');
function verifyMobiusSignature(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const t = parts.t, v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Секрет берётся в админ-панели — действие «Секрет» в строке события (см. Доступ и настройка).
Идемпотентность
Async-события могут прийти повторно (например, ваш сервер ответил, но ответ не
дошёл). Используйте X-Mobius-Delivery (он же id в конверте) как ключ
идемпотентности: если доставку с таким идентификатором уже обработали — верните
2xx, но не выполняйте действие второй раз.
Контракт ответа
Async-события
order.created, order.paid, order.cancelled, bonus.*. Достаточно вернуть
любой 2xx. Тело ответа не используется.
Если вернуть не-2xx или не ответить вовремя — доставка повторяется с
возрастающей паузой (60 / 300 / 900 / 1800 секунд) до заданного в подписке числа
повторов.
Sync-события
order.calculate, order.bonus.calculate, catalog.bonus.calculate. Ответ
влияет на расчёт, поэтому вернуть нужно 2xx со строго одним из двух тел:
{ "ok": true, "data": { } }
{ "ok": false, "error": { "code": "string", "message": "string" } }
- При
ok: trueполеdataсодержит переопределённые значения, специфичные для события (состав корзины, суммы, бонусы — см. OpenAPI документацию). - При
ok: false, а также при любом отклонении (не-2xx, невалидный JSON, таймаут) — расчёт продолжается по умолчанию, без применения вашего ответа. Факт ошибки фиксируется в журнале.
Это «мягкий» контракт: ошибка подписчика никогда не ломает оформление заказа или выдачу каталога — она лишь означает «считай по умолчанию».
Журнал доставок
Вкладка «Журнал» в разделе вебхуков показывает историю доставок: событие, режим, статус, HTTP-код ответа, время ответа, номер попытки и время. Действие «Подробнее» раскрывает тело запроса и ответа.
В журнал попадают все попытки доставки async-событий и все ошибки sync-событий.
Успешные sync-вызовы (включая частый catalog.bonus.calculate) не логируются —
иначе журнал быстро переполнился бы.
Связанные разделы
- Вебхуки — обзор
- Доступ и настройка
- OpenAPI документация — схемы полей по каждому событию.