События и вебхуки
Вам не нужно непрерывно опрашивать (poll) API, чтобы узнавать о тревогах и событиях отправок.
Вы регистрируете HTTPS-адрес, и при возникновении события Frigolive отправляет на него подписанный POST-запрос.
Вебхуки предназначены для доставки событий в защищенный бэкенд-сервис клиента, а не для прямого приема в мобильном приложении.
Настройка
Эндпоинты настраиваются в разделе Настройки → Вебхуки (Settings → Webhooks) панели Frigolive. При сохранении адреса генерируется секрет подписи (signing secret), который отображается ровно один раз. Сохраните его в защищенном хранилище секретов вашего сервиса-обработчика.
На этом же экране вы можете отправить тестовое событие и просмотреть последние 100 попыток доставки с кодами ответов и сообщениями об ошибках.
Публикуемые события
| Событие | Когда происходит | Тело данных |
|---|---|---|
alarm.created | Возникла новая тревога | Запись тревоги (alarm record) |
alarm.resolved | Тревога помечена как решенная | Запись тревоги (alarm record) |
shipment.created | Создана новая отправка | Запись отправки (shipment record) |
shipment.completed | Отправка завершена | Запись отправки (shipment record) |
Каждый эндпоинт получает только те события, на которые он подписан. Добавление новых типов событий
обратно совместимо; если вы получаете неизвестный тип type, просто проигнорируйте его.
Формат запроса
POST /your-receiver-address HTTP/1.1
Content-Type: application/json; charset=utf-8
User-Agent: Frigolive-Webhooks/1.0
X-Frigolive-Event: alarm.created
X-Frigolive-Event-ID: 7126f58a-77c7-4d50-aa87-d1dd99297713
X-Frigolive-Delivery-ID: 0fbc2c15-10ab-4b75-a59e-043b23614b60
X-Frigolive-Timestamp: 1785312000
X-Frigolive-Signature: v1=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
{
"id": "7126f58a-77c7-4d50-aa87-d1dd99297713",
"type": "alarm.created",
"created_at": "2026-07-27T11:42:00Z",
"data": {
"id": "0fbc2c15-10ab-4b75-a59e-043b23614b60",
"device_id": "a6532895-026f-4dad-9f89-432a33e93bc0",
"shipment_id": 481,
"type": "TEMPERATURE",
"severity": "WARNING",
"source": "THRESHOLD",
"message": "Temperature above configured maximum.",
"resolved": false,
"created_at": "2026-07-27T11:42:00Z",
"resolved_at": null
}
}Проверка подписи
Ваш эндпоинт доступен в публичном интернете, и отправить запрос на него может кто угодно. Проверка подписи — единственное доказательство того, что запрос действительно отправлен Frigolive и не был изменен при передаче.
Подписываемая строка имеет формат "{timestamp}.{raw body}" и подписывается алгоритмом HMAC-SHA256.
Используйте исходное тело запроса (raw body): если вы распарсите JSON и затем сериализуете его обратно,
байты изменятся, и подпись не совпадет.
import hashlib
import hmac
import time
TOLERANCE_SECONDS = 300 # 5 минут
def verify(raw_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
# 1) Окно времени: предотвращает атаки повторного воспроизведения (replay attacks).
if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS:
return False
# 2) Пересчет подписи.
signed = f"{timestamp}.".encode() + raw_body
expected = "v1=" + hmac.new(
secret.encode(), signed, hashlib.sha256
).hexdigest()
# 3) Сравнение за постоянное время для предотвращения timing-атак.
return hmac.compare_digest(expected, signature)Аналог на Node.js:
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody: Buffer, timestamp: string, signature: string, secret: string) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected =
"v1=" +
createHmac("sha256", secret)
.update(Buffer.concat([Buffer.from(`${timestamp}.`), rawBody]))
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}Что должен возвращать ваш сервис
Возвращайте статус 2xx в течение 10 секунд. Тело ответа не анализируется; пустой ответ вполне допустим.
Не выполняйте тяжелую обработку синхронно: поместите событие в собственную очередь и немедленно
верните 200. Медленный ответ приведет к таймауту и лишним повторным попыткам отправки.
Повторные попытки и идемпотентность
| Ответ | Поведение |
|---|---|
2xx | Успешно, доставка завершена. |
429 или 5xx | Повтор до 6 раз с экспоненциальной задержкой и джиттером (jitter). |
Любой другой 4xx | Считается постоянной ошибкой, повторные попытки не выполняются. |
| Ошибка соединения / таймаут | Повторная попытка. |
Если ваш ответ потерялся в сети, Frigolive повторит попытку доставки. X-Frigolive-Event-ID не изменяется между попытками — сохраняйте его и пропускайте уже обработанные события. Заголовок X-Frigolive-Delivery-ID уникален для каждой попытки и используется для диагностики.
После 20 последовательных неудачных попыток доставки эндпоинт автоматически отключается, а в панели управления появляется предупреждение. После устранения неполадок вы можете снова включить его на том же экране.
Ротация секрета
Вы можете сгенерировать новый секрет подписи в панели управления. Новый секрет вступает в силу немедленно; если нет ожидающих доставки событий, подписанных старым секретом, процесс пройдет без задержек. Чтобы полностью исключить разрыв, настройте сервис-обработчик на прием обоих секретов в период перехода.
Чек-лист безопасности
- Используйте исключительно
https://— панель отклоняет незащищенныйhttp://. - Проверяйте подпись для каждого запроса; никогда не обрабатывайте непроверенные данные.
- Устанавливайте допустимое отклонение времени (timestamp tolerance) не более 5 минут.
- Храните секрет подписи в менеджере секретов, ни в коем случае не в коде или логах.
- Выполняйте дедупликацию по заголовку
X-Frigolive-Event-ID. - Размещайте эндпоинт по трудноугадываемому URL-пути.