Вебхуки
Настройка вебхуков V2RayTun: типы событий, конфигурация, формат полезной нагрузки.
Обзор
Вебхуки позволяют получать HTTP-уведомления о событиях в панели V2RayTun. При наступлении события панель отправляет POST-запрос на указанный URL с информацией о событии.
Типы событий
| Событие | Описание |
|---|---|
user.expired | Срок действия пользователя истёк |
user.traffic_exceeded | Пользователь исчерпал лимит трафика |
node.offline | Узел потерял связь с панелью |
node.online | Узел восстановил связь с панелью |
Настройка
Через панель
- Перейдите в Settings → Webhooks
- Нажмите Add Webhook
- Укажите URL эндпоинта
- Выберите интересующие события
- Сохраните
Через API
curl -X POST https://panel.example.com/api/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook",
"events": ["user.expired", "node.offline"]
}'Формат полезной нагрузки
Все вебхуки отправляются как POST с Content-Type: application/json.
user.expired
{
"event": "user.expired",
"timestamp": "2025-06-15T12:00:00Z",
"data": {
"userId": "uuid-of-user",
"username": "john",
"expiredAt": "2025-06-15T12:00:00Z"
}
}user.traffic_exceeded
{
"event": "user.traffic_exceeded",
"timestamp": "2025-06-15T12:00:00Z",
"data": {
"userId": "uuid-of-user",
"username": "john",
"trafficUsedBytes": 10737418240,
"trafficLimitBytes": 10737418240
}
}node.offline
{
"event": "node.offline",
"timestamp": "2025-06-15T12:00:00Z",
"data": {
"nodeId": "uuid-of-node",
"nodeName": "Server-DE",
"lastSeen": "2025-06-15T11:55:00Z"
}
}node.online
{
"event": "node.online",
"timestamp": "2025-06-15T12:05:00Z",
"data": {
"nodeId": "uuid-of-node",
"nodeName": "Server-DE"
}
}Обработка вебхуков
Рекомендации
- Отвечайте статусом 200 в течение 5 секунд
- Обрабатывайте вебхуки асинхронно — не блокируйте ответ
- Реализуйте идемпотентность — одно событие может быть доставлено повторно
- Логируйте полученные события для отладки
Пример обработчика (Node.js)
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const { event, data } = req.body;
switch (event) {
case "user.expired":
console.log(`User ${data.username} expired`);
break;
case "node.offline":
console.log(`Node ${data.nodeName} went offline`);
break;
}
res.sendStatus(200);
});
app.listen(3000);Пример обработчика (Python)
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def handle_webhook():
payload = request.json
event = payload["event"]
data = payload["data"]
if event == "user.expired":
print(f"User {data['username']} expired")
elif event == "node.offline":
print(f"Node {data['nodeName']} went offline")
return "", 200Повторные попытки
При неудачной доставке (не-2xx ответ или таймаут) панель повторяет отправку:
- 1-я повторная попытка через 30 секунд
- 2-я через 5 минут
- 3-я через 30 минут
После 3 неудачных попыток событие помечается как недоставленное.