A Aurum
← Все статьи

Уведомления без ошибок: подпись, повторы и порядок

Вебхук — это HTTP-запрос на открытый адрес вашего сервера. Всё, что о нём известно по умолчанию: кто-то прислал JSON. Три вещи превращают его в надёжный сигнал об оплате.

Подпись: иначе отгрузить может кто угодно

Адрес уведомлений открыт всему интернету. Если обработчик верит телу запроса, то отгрузить заказ может любой, кто угадал адрес и формат — а формат описан в документации.

Поэтому каждое уведомление подписано секретом проекта: Aurum-Signature: t=<время>,v1=<hmac-sha256>. Подпись считается от строки <время>.<тело>.

Проверяйте её до разбора тела и до любых действий с заказом. И обязательно по сырым байтам: тело, прошедшее через JSON.parse и обратно, отличается пробелами и порядком полей — подпись к нему не сойдётся, и вы потратите день, решив, что «подпись не работает».

Сравнивайте подписи функцией постоянного времени (timingSafeEqual, hash_equals). Обычное сравнение строк выходит на первом различии, и по времени ответа подпись подбирается побайтово.

Отметка времени: чтобы вчерашнее не сработало сегодня

Время входит в подписываемую строку не для красоты. Без него перехваченное уведомление остаётся годным вечно: достаточно повторить тот же запрос через неделю. С ним получатель сверяет возраст — старше пяти минут отвергается.

Повторы: доставка «хотя бы один раз»

Если ваш сервер ответил ошибкой или не ответил вовсе, уведомление придёт снова — с нарастающими паузами. Это значит, что одно и то же событие вы увидите несколько раз, и обработчик обязан это выдерживать.

Правильный способ — идемпотентность по состоянию, а не по факту получения: не «я это уже видел», а «заказ уже оплачен, делать нечего». Первый подход ломается при потере журнала, второй — нет.

if (order.status === 'paid') return res.sendStatus(200)   // уже отгружено
order.status = 'paid'
ship(order)

Порядок: его нет

Уведомления не гарантируют порядок. По одному счёту может прийти invoice.underpaid, затем invoice.paid — а при повторной доставке первого вы увидите «недоплачено» после «оплачено».

Не стройте логику на последовательности. Ориентируйтесь на поля: received и amount в теле говорят всё, что нужно, независимо от того, какое уведомление пришло раньше.

Отвечайте быстро

Обработчик должен вернуть 200 и завершиться. Отправка письма, генерация чека, обращение к складу — всё это в очередь. Долгий ответ приводит к таймауту, таймаут — к повторной доставке, а повторная доставка при неидемпотентном обработчике — ко второй отгрузке.

Проверочный список