POST-запрос на ваш URL с данными события.
200, 201 или 202 (таймаут ответа — 15 секунд).Как это работает
Событие фиксируется
PaymentCompleted) с таймстемпом и параметрами инициатора.Поиск активных эндпоинтов
Сборка полезной нагрузки
data,
единый idempotencyKey и timestamp. Лишние поля вырезаются по строгой схеме (allow-list).Отправка с подписью и повторы
POST-запросом с заголовком signature (HMAC-SHA256). Если приёмник не ответил
200/201/202 — выполняется до 5 попыток с нарастающей задержкой.active = false или удалите его.Формат сообщения
Тело запроса — JSON-объект следующей структуры:Проверка подписи
В каждом запросе передаётся заголовокsignature — это HMAC-SHA256 (hex) от сырого тела запроса,
подписанного секретным ключом вашего эндпоинта.
secretKey передаётся в HMAC как есть, как ASCII/UTF-8 строка из 64 символов. Несмотря на внешний
вид, его не нужно декодировать из hex или base64. Результат подписи — строка из 64 hex-символов в
нижнем регистре, без префикса sha256=.Доставка и повторные попытки
200/201/202, а также таймаут или сетевая ошибка считаются неуспехом и приводят к
повторной попытке. После 5 неудачных попыток событие помечается как failed и больше не отправляется.Управление эндпоинтами
Эндпоинты вебхуков настраиваются в админ-панели школы (раздел настроек). Для каждого эндпоинта задаётся:url— HTTPS-адрес приёмника (до 255 символов);events— список событий, на которые он подписан;active— флаг активности (по умолчаниюtrue);note— произвольная заметка;secretKey— секрет для проверки подписи, генерируется автоматически при создании эндпоинта.
secretKey создаётся вместе с эндпоинтом и доступен в
настройках вебхука в админ-панели школы. Скопируйте его и сохраните в переменных окружения вашего
сервиса (в примерах ниже — EXODE_WEBHOOK_SECRET). Если секрет не отображается — запросите его у
поддержки.Тестовая отправка
Тестовая отправка из формы сохранённого эндпоинта подписывается его жеsecretKey. Формат тела,
алгоритм и заголовок полностью совпадают с боевыми событиями, поэтому приёмнику не нужна отдельная ветка
проверки для тестовых вебхуков.
Поддерживаемые события
Ниже — события, которые реально доставляются, и структура их поляdata. Вложенные сущности
(user, profile, course, payment и др.) описаны в справочнике объектов.
UserSignedUp — регистрация пользователя
UserSignedUp — регистрация пользователя
data:user— объект пользователя.profile— карточка профиля (null, если не заполнена).states.utmSignupParams— объект UTM-меток первичного визита (опционально).
UserAcquainted — завершён онбординг
UserAcquainted — завершён онбординг
data идентична UserSignedUp
(user, profile, states.utmSignupParams).UserTgConnected — привязан Telegram
UserTgConnected — привязан Telegram
data:user— объект пользователя (с актуальнымtgId).profile— карточка профиля (опционально).prevTgId— предыдущийtgIdдля отслеживания перепривязки (number | null).
CourseProgressChanged — изменился прогресс по уроку
CourseProgressChanged — изменился прогресс по уроку
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).groups— массив групп пользователя в курсе (опционально).status— новый статус урока (CourseProgressLessonStatus, опционально).lessonId— ID урока (опционально).
CourseCompleted — курс завершён
CourseCompleted — курс завершён
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).groups— массив групп (опционально).
CourseLessonPracticeCompleted — пройдена практика
CourseLessonPracticeCompleted — пройдена практика
data:user— пользователь с профилем.course— курс (опционально).lesson— урок (опционально).practice— параметры практики (опционально).attempt— попытка прохождения с баллами и статусом (опционально).variantId— ID варианта (опционально).
PaymentCompleted — оплата прошла успешно
PaymentCompleted — оплата прошла успешно
data.payment — объект платежа с полным деревом: invoice
(счёт), invoice.user (покупатель с профилем и школой), invoice.products (позиции с продуктом/курсом,
ценой и скидкой), acquiring (эквайринг и провайдер, без секретов). Денежные поля — числа.Событие отправляется только при реальном списании денег: инициализация рекуррента (привязка карты,
нулевой платёж со статусом BindingCompleted) вебхук не вызывает.ProductEnrolledToFree — выдан бесплатный доступ
ProductEnrolledToFree — выдан бесплатный доступ
data:user— пользователь.profile— карточка профиля (опционально).access— объект доступа (опционально).product— продукт (опционально).course— курс (опционально).
ProductEnrolledViaLms — доступ выдан вручную (LMS)
ProductEnrolledViaLms — доступ выдан вручную (LMS)
data идентична ProductEnrolledToFree (user, profile, access, product, course).ProductEnrolledViaPayment — доступ выдан после оплаты
ProductEnrolledViaPayment — доступ выдан после оплаты
data идентична ProductEnrolledToFree (user, profile, access, product, course).ProductEnrolledByInviteLink — запись по ссылке-приглашению
ProductEnrolledByInviteLink — запись по ссылке-приглашению
data: те же поля, что и у ProductEnrolledToFree (user, profile, access, product, course),
плюс:inviteLinkId— идентификатор ссылки, по которой пришёл пользователь.
CertificateIssued — выдан сертификат
CertificateIssued — выдан сертификат
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).certificate— объект сертификата с публичной ссылкойlink(открывается без авторизации), сроком действия и слепком данных на момент выдачи.
UserSignedIn, UserLoggedOut, UserJoinedByReferral, UserCreatedViaLms,
CourseLessonPracticeDetailedSent, CourseLessonPracticeAutoVerifySent, ProductRefundCompleted,
ProductAccessSubscriptionEnding7Days и ProductAccessSubscriptionEnding1Day можно подписаться, но
формальный контракт data для них ещё не зафиксирован — состав полезной нагрузки не гарантируется.
Перед использованием сверьтесь с поддержкой.Пример: PaymentCompleted
Тело ниже — реальный пример тестовой отправки (синтетические значения, точный состав полей):Диагностика
Повторные попытки
Повторные попытки
idempotencyKey. Задержки отсчитываются от предыдущей
неудачной попытки (≈11 / 22 / 44 / 88 / 176 минут). Верните успешный код, чтобы остановить повторы.Временное отключение
Временное отключение
active = false, чтобы приостановить доставку без потери конфигурации и секретного ключа.Логирование
Логирование
event, timestamp, idempotencyKey и результат проверки подписи — это ускорит сверку с
нашей стороной при разборе инцидентов.Обновлено: 2026-08-03 10:28 UTC