> ## Documentation Index
> Fetch the complete documentation index at: https://faq.exode.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Вебхуки

> Настройка вебхуков школы: события, URL эндпоинтов, формат payload, тестовые события и проверка подписи

Вебхуки позволяют школе автоматически уведомлять внешние сервисы о событиях: регистрации ученика,
успешной оплате, завершении курса и других. Когда событие происходит, платформа отправляет HTTP-запрос
(POST) на указанный вами URL с данными события. Это основной способ интеграции школы с CRM, чат-ботами,
системами рассылок и собственными сервисами.

Настройка находится в разделе **Управление → Школа → Вебхуки** (`/manage/school/webhooks`).

<img src="https://mintlify.s3.us-west-1.amazonaws.com/exode-faq/images/online-schools/developers/webhooks-list.png" alt="Список вебхуков школы" />

## Как создать вебхук

<Steps>
  <Step title="Откройте раздел «Вебхуки»">
    Перейдите в управление школой и выберите «Вебхуки». Нажмите **Создать вебхук**.
  </Step>

  <Step title="Укажите URL эндпоинта">
    Введите адрес, на который платформа будет отправлять запросы (до 255 символов). При желании
    добавьте служебную заметку (`note`) — она видна только в списке и помогает не путать эндпоинты.
  </Step>

  <Step title="Выберите события">
    Отметьте события, о которых хотите получать уведомления. Счётчик показывает количество выбранных.
  </Step>

  <Step title="Проверьте и сохраните">
    Отправьте тестовое событие (кнопка-стрелка рядом с событием), убедитесь, что ваш сервер принимает
    запрос, и сохраните вебхук.
  </Step>
</Steps>

<img src="https://mintlify.s3.us-west-1.amazonaws.com/exode-faq/images/online-schools/developers/webhook-form.png" alt="Форма создания вебхука с выбором событий" />

Каждый эндпоинт можно включать и выключать переключателем в списке (`active`), редактировать и удалять.

## Доступные события

Ниже — события, доступные для подписки в интерфейсе школы. Идентификаторы соответствуют значениям
enum `WebhookEvent` на сервере.

### Пользователи

| Событие                             | Идентификатор          | Когда срабатывает                                        |
| ----------------------------------- | ---------------------- | -------------------------------------------------------- |
| Пользователь зарегистрировался      | `UserSignedUp`         | Успешная самостоятельная регистрация нового пользователя |
| Присоединился по реферальной ссылке | `UserJoinedByReferral` | Регистрация через реферальную ссылку                     |
| Пользователь создан через LMS       | `UserCreatedViaLms`    | Новый пользователь создан вручную через LMS              |
| Пользователь вошёл в систему        | `UserSignedIn`         | Успешная авторизация пользователя                        |
| Пользователь вышел из системы       | `UserLoggedOut`        | Выход из аккаунта                                        |
| Подключил Telegram                  | `UserTgConnected`      | Привязка или смена Telegram ID                           |
| Пользователь заполнил данные        | `UserAcquainted`       | Отправлена форма знакомства                              |

### Курсы и практика

| Событие                         | Идентификатор                        | Когда срабатывает                           |
| ------------------------------- | ------------------------------------ | ------------------------------------------- |
| Курс завершён                   | `CourseCompleted`                    | Все доступные модули и уроки курса пройдены |
| Прогресс курса изменён          | `CourseProgressChanged`              | У пользователя изменился прогресс           |
| Практика успешно пройдена       | `CourseLessonPracticeCompleted`      | Практика переведена в статус «Пройдена»     |
| Практика отправлена на проверку | `CourseLessonPracticeDetailedSent`   | Практика отправлена куратору на проверку    |
| Практика авто-проверена         | `CourseLessonPracticeAutoVerifySent` | Автоматическая проверка практики урока      |

### Продукты и доступ

| Событие                        | Идентификатор                          | Когда срабатывает                         |
| ------------------------------ | -------------------------------------- | ----------------------------------------- |
| Запись на бесплатный курс      | `ProductEnrolledToFree`                | Пользователь записался на бесплатный курс |
| Запись через LMS               | `ProductEnrolledViaLms`                | Пользователь записан вручную через LMS    |
| Запись через оплату            | `ProductEnrolledViaPayment`            | Запись на курс через успешную оплату      |
| Возврат средств завершён       | `ProductRefundCompleted`               | Успешно обработан возврат средств         |
| Подписка истекает через 7 дней | `ProductAccessSubscriptionEnding7Days` | Срок подписки истекает через 7 дней       |
| Подписка истекает через 1 день | `ProductAccessSubscriptionEnding1Day`  | Срок подписки истекает через 1 день       |

### Платежи

| Событие         | Идентификатор      | Когда срабатывает       |
| --------------- | ------------------ | ----------------------- |
| Платёж завершён | `PaymentCompleted` | Успешная оплата платежа |

<Note>
  На сервере enum `WebhookEvent` содержит дополнительные системные события (например, служебные cron-события
  и события уровня школы). В интерфейсе школы для подписки доступен только список выше — остальные события
  зарезервированы для внутреннего использования и могут быть недоступны для выбора.
</Note>

## Формат payload

Платформа отправляет на ваш URL POST-запрос с телом в формате JSON. Тело содержит тип события и его данные.
Пример полезной нагрузки для события оплаты:

```json theme={null}
{
  "event": "PaymentCompleted",
  "schoolId": 42,
  "data": {
    "paymentId": 100500,
    "userId": 7788,
    "amount": 4990,
    "currency": "RUB"
  }
}
```

<Note>
  Точный состав полей объекта `data` зависит от конкретного события и определяется на стороне сервера.
  Перед запуском интеграции проверьте реальную структуру, отправив **тестовое событие** на свой эндпоинт
  и залогировав входящий запрос. Тестовое событие отправляется кнопкой-стрелкой напротив события в форме вебхука.
</Note>

## Тестовые события

Прямо в форме вебхука, не сохраняя эндпоинт, можно отправить тестовое событие на указанный URL —
для этого рядом с каждым доступным событием есть кнопка отправки. Так удобно проверить, что ваш сервер
корректно принимает запросы и разбирает payload, ещё до включения вебхука в бой.

## Безопасность и подпись

Для каждого эндпоинта платформа генерирует секретный ключ подписи (`secretKey`). Его можно скопировать
из меню действий эндпоинта (пункт **Скопировать подпись**) или из формы редактирования вебхука.

Ключ используется, чтобы ваш сервер мог убедиться, что запрос пришёл именно от платформы, а не от
стороннего источника. Проверяйте подпись на входящих запросах и обрабатывайте только те, что прошли проверку.

<Warning>
  Секретный ключ подписи — чувствительные данные. Не публикуйте его в клиентском коде и в открытых репозиториях.
  Точный алгоритм и заголовок подписи уточните в технической поддержке платформы перед реализацией проверки —
  не полагайтесь на предположения.
</Warning>

<Tip>
  Отвечайте на вебхук HTTP-статусом `2xx` как можно быстрее. Тяжёлую обработку выносите в фоновую очередь,
  чтобы не задерживать ответ и не провоцировать повторные попытки доставки.
</Tip>
