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 и больше не отправляется.Управление эндпоинтами
Эндпоинты вебхуков настраиваются в кабинете: Управление → Школа → Вебхуки (/manage/school/webhooks).
Нужно право «Управление настройками школы» (SchoolManageSettings). Через SaaS API эндпоинты не управляются.
Для каждого эндпоинта задаётся:
url— адрес приёмника (до 255 символов); используйте HTTPS;events— список событий, на которые он подписан;active— флаг активности (по умолчаниюtrue);note— произвольная заметка (до 255 символов);secretKey— секрет для проверки подписи, генерируется автоматически при создании эндпоинта.
secretKey создаётся вместе с эндпоинтом. В кабинете он
копируется командой «Копировать подпись» — в меню строки эндпоинта или рядом с полем URL в его форме
(несмотря на название, копируется именно секрет, а не готовая подпись). Сохраните его в переменных окружения
вашего сервиса (в примерах выше — 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).
UserCreatedViaLms — школа создала пользователя
UserCreatedViaLms — школа создала пользователя
user/create и user/upsert
(только когда upsert создаёт пользователя, а не обновляет существующего). Самостоятельная регистрация
пользователя приходит отдельным событием UserSignedUp.data:user— объект пользователя.profile— карточка профиля (опционально).
CourseProgressChanged — изменился прогресс по уроку
CourseProgressChanged — изменился прогресс по уроку
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).access— доступ пользователя к продукту курса (опционально).states.utmEnrollParams,states.utmSignupParams— UTM-метки записи и регистрации, см. UTM-атрибуция.groups— массив групп пользователя в курсе (опционально).status— новый статус урока из записи прогресса (опционально):NotStarted,OnTheory,OnPractice,OnReview,OnCorrectionилиCompleted— расшифровка вcourseProgress.lessonId— ID урока (опционально).
CourseCompleted — курс завершён
CourseCompleted — курс завершён
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).access— доступ пользователя (опционально).states.utmEnrollParams,states.utmSignupParams— UTM-метки записи и регистрации, см. UTM-атрибуция.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— объект доступа (опционально).states.utmEnrollParams,states.utmSignupParams— UTM-метки записи и регистрации, см. UTM-атрибуция.product— продукт (опционально).course— курс (опционально).
ProductEnrolledViaLms — доступ выдан вручную (LMS)
ProductEnrolledViaLms — доступ выдан вручную (LMS)
data идентична ProductEnrolledToFree (user, profile, access, product, course, states).ProductEnrolledViaPayment — доступ выдан после оплаты
ProductEnrolledViaPayment — доступ выдан после оплаты
data идентична ProductEnrolledToFree (user, profile, access, product, course, states).ProductEnrolledByInviteLink — запись по ссылке-приглашению
ProductEnrolledByInviteLink — запись по ссылке-приглашению
data: те же поля, что и у ProductEnrolledToFree (user, profile, access, product, course, states),
плюс:inviteLinkId— идентификатор ссылки, по которой пришёл пользователь (дублируется вaccess.meta.inviteLinkId).
CertificateIssued — выдан сертификат
CertificateIssued — выдан сертификат
data:user— пользователь с профилем.course— объект курса.product— продукт курса (опционально).certificate— объект сертификата с публичной ссылкойlink(открывается без авторизации), сроком действия и слепком данных на момент выдачи.
UserSignedIn, UserLoggedOut, UserJoinedByReferral,
CourseLessonPracticeDetailedSent, CourseLessonPracticeAutoVerifySent, ProductRefundCompleted,
ProductAccessSubscriptionEnding7Days и ProductAccessSubscriptionEnding1Day можно подписаться, но
формальный контракт data для них ещё не зафиксирован — состав полезной нагрузки не гарантируется.
Перед использованием сверьтесь с поддержкой.UTM-атрибуция
UTM-метки приходят в трёх местах в зависимости от события:utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid, fbclid, yclid,
referrer, aff_id, sub_id, track_id (присутствуют только переданные). Если пользователь пришёл без меток, объект
отсутствует или пуст.
Пример: PaymentCompleted
Тело ниже — реальный пример тестовой отправки (синтетические значения, точный состав полей):Диагностика
Повторные попытки
Повторные попытки
idempotencyKey. Задержки отсчитываются от предыдущей
неудачной попытки (≈ 11 / 33 / 77 / 165 минут). Верните успешный код, чтобы остановить повторы.Временное отключение
Временное отключение
active = false, чтобы приостановить доставку без потери конфигурации и секретного ключа.
Повторы событий, которые встали в очередь до выключения, прекращаются после ближайшей неудачной попытки.Логирование
Логирование
event, timestamp, idempotencyKey и результат проверки подписи — это ускорит сверку с
нашей стороной при разборе инцидентов.Обновлено: 2026-09-28 05:04 UTC