Обзор
Получайте события TicketWave в виде подписанных HTTP-запросов в своём приложении.
Вебхуки
Вебхук — это HTTP-запрос, который TicketWave отправляет вам. Каждый раз, когда на вашем сервере что-то происходит — открывается тикет, участник попадает в чёрный список — TicketWave отправляет POST с JSON-телом на принадлежащий вам URL.
В этом и есть отличие от Log Channels: log channels записывают embed в Discord для чтения людьми, а вебхуки передают сырое событие прямо в ваш код.
Вебхуки — это премиум-функция. Без премиума эндпоинты нельзя создать, и события не будут доставляться.
Создание эндпоинта
Откройте страницу эндпоинтов
Панель сервера → Webhooks → Endpoints.
Добавьте эндпоинт
Нажмите Add Endpoint и заполните два поля:
| Field | Description |
|---|---|
| Endpoint URL | URL с https://, на который будут приходить запросы |
| Event Types | Какие события должен получать этот эндпоинт |
Эндпоинт получает только те типы, которые вы отметите. Выбрать ничего нельзя — укажите как минимум один тип.
Скопируйте секрет подписи
TicketWave генерирует секрет подписи (whsec_…) в момент создания эндпоинта. Откройте список эндпоинтов, покажите его с помощью значка глаза и скопируйте в конфигурацию вашего приложения.
Относитесь к секрету как к паролю. Любой, у кого он есть, может подделать запросы, которые пройдут проверку подписи. Храните его в переменной окружения, никогда не в репозитории.
Отправьте тестовое событие
Используйте кнопку Send test event (бумажный самолётик) в строке эндпоинта. Она отправляет настоящий, полностью подписанный запрос с "test": true в полезной нагрузке, чтобы вы могли убедиться, что ваш приёмник работает, ещё до того, как на него будет зависеть реальный тикет.
Результат появится в истории Webhooks как и любая другая доставка.
Требования к эндпоинту
| Requirement | Detail |
|---|---|
| Scheme | Только https:// — http:// отклоняется |
| Host | Должен быть публично разрешаемым. Частные, loopback, link-local и CGNAT-адреса отклоняются |
| Response | Любой статус 2xx считается успехом |
| Timeout | На ответ у вас есть 10 секунд |
| Redirects | Не следуются. 3xx считается ошибкой |
| Limit | До 5 эндпоинтов на сервер |
Проверка хоста выполняется и при сохранении эндпоинта, и перед каждой отдельной доставкой, поэтому домен, который позже начнёт разрешаться во внутренний адрес, перестанет получать события.
Запрос
Каждая доставка — это POST с JSON-телом.
Заголовки
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | Всегда JSON |
User-Agent | TicketWave-Webhooks/1.0.5 | Версия бота, который отправил запрос |
X-TicketWave-Event | ticket.created | Тип события |
X-TicketWave-Delivery | wh_3f2a… | Уникальный id этой доставки |
X-TicketWave-Timestamp | 1786224191 | Unix-время в секундах, часть подписи |
X-TicketWave-Signature | sha256=9f86d0… | HMAC запроса |
Тело
Каждая полезная нагрузка использует одну и ту же оболочку. Отличается только data для каждого типа события:
{
"event": "ticket.created",
"timestamp": "2026-08-26T08:23:11.000Z",
"guild_id": "123456789012345678",
"data": {
"ticket_id": "ticket-1042",
"ticket_num_id": 1042,
"channel_id": "998877665544332211",
"category": "🤖 Support",
"user": { "id": "987654321098765432", "username": "Luna" },
"created_at": "2026-08-26T08:23:11.000Z"
}
}См. Event Reference для объекта data каждого типа.
Проверка подписи
Любой, кто узнает URL вашего эндпоинта, может отправить на него POST-запрос. Подпись нужна, чтобы отличить настоящую доставку TicketWave от поддельной.
Всегда проверяйте. Непроверенный эндпоинт, который создаёт или закрывает что-то в вашей системе, — это открытая дверь.
Как формируется подпись
TicketWave соединяет timestamp и сырой body запроса через точку и вычисляет HMAC-SHA256 от результата, используя секрет вашего эндпоинта:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)В заголовке этот дайджест передаётся в hex-формате и с префиксом: sha256=<digest>.
Что должен делать ваш приёмник
Считывайте сырой body. Проверяйте его по точным байтам, которые вы получили. Если ваш фреймворк сначала парсит JSON, а потом вы сериализуете его заново, порядок ключей или пробелы могут измениться, и дайджест не совпадёт.
Пересчитывайте HMAC по timestamp + "." + rawBody с вашим секретом.
Сравнивайте в постоянное время (crypto.timingSafeEqual в Node). Обычный === раскрывает информацию по времени выполнения.
Проверяйте, что timestamp свежий — хороший стандарт по умолчанию: допуск в пять минут. Timestamp находится внутри подписанной полезной нагрузки, поэтому злоумышленник не сможет повторно отправить старый запрос с новым timestamp.
Полная реализация есть на странице Example Server.
Повторы
Неудачная доставка автоматически повторяется.
| Attempts | 3 (первая попытка плюс 2 повтора) |
| Backoff | 1 секунда, затем 5 секунд |
| Retried on | Ошибки сети, таймауты, 408, 429 и любые 5xx |
| Not retried on | Все остальные 4xx — они означают, что ваш эндпоинт намеренно отклонил запрос |
Из-за повторов ваш эндпоинт может получить одно и то же событие дважды. Используйте X-TicketWave-Delivery как ключ идемпотентности: запоминайте уже обработанные id и игнорируйте повторы.
Доставки не упорядочены. Если два тикета создаются одновременно, запросы могут прийти в любом порядке — используйте поле timestamp в теле, если порядок для вас важен.
История доставок
На странице Webhooks в панели отображаются все доставки со статусом, кодом ответа, длительностью и числом попыток. Откройте строку, чтобы увидеть точную полезную нагрузку запроса и ответ, который вернул ваш сервер.
Неудачные доставки можно отправить повторно со страницы деталей с помощью Retry Webhook. Он снова отправляет исходную полезную нагрузку на тот же эндпоинт и записывает новую доставку.
История хранится 30 дней, после чего автоматически очищается.
Устранение неполадок
| Problem | Fix |
|---|---|
| Эндпоинт не удаётся сохранить | URL должен начинаться с https:// и разрешаться в публичный адрес |
| Всё отображается как неудачное, без кода ответа | Запрос до вас так и не дошёл — таймаут, сбой DNS или отказ в соединении |
| Подпись никогда не совпадает | Вы хэшируете распарсенное тело вместо сырых байтов или забыли префикс timestamp + "." |
| Доставки через некоторое время прекращаются | Проверьте, не начал ли ваш хост возвращать 4xx — они не повторяются |
| Событие так и не приходит | Эндпоинт не подписан на этот тип, либо сервер потерял премиум |
| Дублирующиеся события | Ожидаемо при повторах — дедуплицируйте по X-TicketWave-Delivery |
Следующие шаги
- Event Reference (Каждое событие и его полезная нагрузка)
- Example Server (Рабочий приёмник на Express)
- Log Channels (Те же события, но отправляются в Discord)
How is this guide?
