REST API v1 · 13 эндпоинтов · SDK на PyPI

Документация REST API

Автоматизируйте создание ключей, баланс и webhooks. Быстрый путь — pip install whitelisthub. Минимальный ключ — 1 GB (≈ 5 ₽/мес). Token и sandbox — после входа.

Base URL
https://whitelisthub.net/api/v1
Authorization
Bearer <api_token>
или заголовок X-API-Token
Python SDK
pip install whitelisthub
PanelClient · keys · balance · pricing
JSON · UTF-8 Idempotency-Key whitelisthub 1.1.0 Sandbox token — без списания Webhooks: key.created, payment.*

Python SDK · whitelisthub 1.1.0

Официальный клиент на PyPI. Баланс, создание/renew ключей, quote, Bedolaga — без ручных заголовков. Токен берёте в панели → API.

PyPI Полный гайд ↓
pip install whitelisthub

from whitelisthub import PanelClient

c = PanelClient("https://whitelisthub.net", api_token="YOUR_TOKEN")
print(c.balance())
key = c.keys.create(limit_gb=50, months=1, idempotency_key="ord-1")
print(key["key_id"], key.get("subscription_url"))
Ничего не найдено

REST API панели

Base URL: https://ВАШ_ДОМЕН/api/v1 — домен вашей панели (не путать с доменом подписки клиентов).

Python SDK (whitelisthub)

Официальный клиент на PyPI — без ручной сборки HTTP-заголовков.

bash
pip install whitelisthub
python
from whitelisthub import PanelClient

client = PanelClient("https://whitelisthub.net", api_token="YOUR_TOKEN")

# баланс
bal = client.balance()

# создать ключ (Idempotency-Key рекомендуется)
key = client.keys.create(limit_gb=50, months=1, idempotency_key="ord-1")
print(key["key_id"], key.get("subscription_url"))

# список / info / renew
client.keys.list()
client.keys.get("KEY_ID")
client.keys.renew("KEY_ID", months=1)

Пакет: pypi.org/project/whitelisthub · версия 1.1.0+.

Токен — в панели → API. Sandbox-token создаёт mock-ключи SBX_ без списания.

Два разных URL

ЧтоГде настраиваетсяПример
Ваш домен подпискиПанель → Подписка → публичный домен (или домен от админа)https://sub.ваш-домен.ru/sub/KEY_ID
merge_sub_url (опционально)При создании/редактировании конкретного ключа — ссылка подписки клиента у другого провайдераhttps://sub.другой-сервис.ru/токен_клиента

Клиент в Happ открывает ваш subscription_url. Поле merge_sub_url — только если нужно подтянуть vless из чужой подписки этого клиента в ваш /sub/KEY.

Авторизация: заголовок Authorization: Bearer <api_token> или X-API-Token: <api_token>.

Токен выдаётся в личном кабинете → API.

GET /balance

Баланс tenant и платформы.

Ответ:

json
{
  "success": true,
  "balance_rub": 1500.0,
  "app_name": "MyVPN",
  "platform_balance_rub": 50000,
  "platform_ok": true
}
platform_balance_rub в API — отображаемое значение (×1000 от фактического баланса VPN-платформы). Например, при 50 ₽ на upstream API в ответе будет 50000.
GET /keys

Список всех ключей tenant (включая client_user_id, client_login, note как comments, merge_sub_url, status).

GET /pricing

Ставки партнёра + меню пакетов + лимиты заказа.

Ответ (фрагмент):

  • rates.create_gb_month / renew_gb / reset_gb / expand_gb
  • min_order_gb / max_order_gb
  • large_gb_threshold (1000), short_term_days (7), upstream_cost_per_1000_gb (400)
  • packages — пресеты 10/100/1000/10000 с ценами по срокам + short_term_price / renew_locked
  • package_prices — карта "GB:months" и "GB:d7" → ₽
  • formulas.create — меню со скидкой; ≥1000 кастом — объёмная скидка; 7д на ≥1000 — премиум; иначе ставка
  • formulas.renew — ключи ≥1000 ГБ только через админа
GETPOST /pricing/quote

Предрасчёт стоимости создания ключа без списания.

bash
curl "https://whitelisthub.net/api/v1/pricing/quote?limit=10&months=1" -H "Authorization: Bearer TOKEN"
curl -X POST "https://whitelisthub.net/api/v1/pricing/quote" -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" -d '{"limit":1000,"months":1}'
curl -X POST "https://whitelisthub.net/api/v1/pricing/quote" -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" -d '{"limit":1000,"months":1,"days":7}'

Ответ: cost_rub, pricing_mode (package | large_volume | short_term_large | rate), days, rate_create_gb.

GETPOST /keys/search

Поиск только среди своих ключей.

Параметры (query или JSON):

ПолеОписание
qОбщий поиск: key_id, user_id, login, comments, merge_url, limit
user_idФильтр по client_user_id
loginФильтр по client_login
commentsФильтр по комментарию (note)
limitМакс. результатов (по умолчанию 100)

Пример:

bash
curl "https://whitelisthub.net/api/v1/keys/search?q=ivan" -H "Authorization: Bearer TOKEN"
POST /key/create

Создание ключа. Списание с баланса автоматически.

Тело:

json
{
  "limit": 50,
  "months": 3,
  "days": 7,
  "user_id": "12345",
  "login": "ivanov",
  "comments": "Клиент Telegram",
  "merge_sub_url": "https://sub.другой-провайдер.ru/токен_клиента"
}
ПолеОбязательноОписание
limit / limit_gbдаЛимит ГБ ≥ 1
monthsнетСрок, по умолчанию 1
daysнет7 — короткий премиум-срок только для ≥1000 ГБ (цена без скидок, в разы выше)
user_id / useridнетВнешний ID клиента (для поиска и %user_id% в Happ)
loginнетЛогин клиента
comments / comment / noteнетКомментарий
merge_sub_url / merge_url / external_subнетНе ваш домен. URL подписки клиента у другого провайдера — vless добавятся в ваш /sub/KEY

Ответ: key_id, subscription_url, cost_rub, pricing_mode, balance_rub, метаданные клиента.

Продление (POST /key/renew): для ключей ≥1000 ГБ возвращает renew_locked_large_key — только через админа (impersonate).

При merge_sub_url в подписке Happ будут ваши сервера (upstream) + их vless из указанного URL.

Idempotency (защита от двойного списания):

Заголовок Idempotency-Key: <уникальная строка 8–128 символов>.

  • Повтор запроса с тем же ключом и тем же телом → тот же ответ, без повторного списания (idempotent_replay: true).
  • Другой body с тем же ключом → 422 idempotency_key_mismatch.
  • Запрос ещё выполняется → 409 idempotency_in_progress.
bash
curl -X POST "https://whitelisthub.net/api/v1/key/create" \
  -H "Authorization: Bearer TOKEN" \
  -H "Idempotency-Key: order-2026-001" \
  -H "Content-Type: application/json" \
  -d '{"limit":50,"months":1}'
PATCHPOST /key/update

Обновление метаданных ключа без списания. Передавайте только нужные поля.

json
{
  "key": "KEY_ID",
  "user_id": "12345",
  "login": "ivanov",
  "comments": "VIP клиент",
  "merge_sub_url": "https://sub.example.com/token"
}
ПолеОписание
key / key_idобязательно
user_id / useridвнешний ID клиента
loginлогин
comments / comment / noteкомментарий
merge_sub_url / merge_url / external_subподписка этого клиента у другого провайдера (не домен панели)

Пустая строка "" очищает поле. Кэш /sub/ инвалидируется автоматически.

POST /key/info
json
{"key": "KEY_ID"}

Возвращает трафик upstream + client_user_id, client_login, comments, merge_sub_url, panel_status.

POST /key/renew

Продление срока (месяцы). Не для LIMITED.

json
{"key": "KEY_ID", "months": 1}

Если ключ LIMITED / трафик исчерпан → 400 use_reset_not_renew. Нужен /key/reset.

POST /key/expand
json
{"key": "KEY_ID", "limit": 100}
POST /key/reset

Сброс счётчика трафика (used × reset_gb). Срок не меняется. Это правильная операция для LIMITED.

json
{"key": "KEY_ID"}
POST /key/ban

Блокировка ключа (клиенты получают stub на /sub/).

json
{
  "key": "KEY_ID",
  "message": "Подписка заблокирована. Поддержка: @bot"
}

Разблокировка:

json
{"key": "KEY_ID", "unblock": true}
POST /key/delete

Мягкое удаление (status=deleted, /sub/ → 404).

json
{"key": "KEY_ID"}

Переменные в Happ (announce, sub-info-text)

В настройках подписки tenant:

ПеременнаяИсточник
%gb_limit%Лимит ГБ
%gb_used% / %gb_use%Использовано
%gb_left% / %gb_ostalos%Осталось
%user_id%client_user_id ключа
%login%client_login
%comments%note / comments
%expire_date%, %days_left%, %app_name%, %key_short%как раньше

Happ meta-заголовки

Настраиваются в панели → Подписка:

UIHTTP-заголовок
Цвет блокаsub-info-color (red/blue/green)
Текстsub-info-text
Кнопкаsub-info-button-text + sub-info-button-link
Истечениеsub-expire: 1
Продлитьsub-expire-button-link

Документация Happ: https://www.happ.su/main/ru/dev-docs/app-management

Уведомления Telegram

При списаниях и пополнениях баланса tenant админы с включёнными настройками получают сообщения:

  • Списание (debit_create_key, debit_reset_traffic, debit_expand, …) — «💸 Списание N ₽»
  • Пополнение (credit, payment, referral_to_balance) — «💰 Пополнение +N ₽»

Включение: админ-панель → Telegram → уведомления debit / topup.

Примеры curl

bash
# Поиск по user_id
curl "https://whitelisthub.net/api/v1/keys/search?user_id=12345" -H "Authorization: Bearer TOKEN"

# Создание с merge подпиской
curl -X POST "https://whitelisthub.net/api/v1/key/create" \
  -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
  -d '{"limit":50,"months":1,"merge_sub_url":"https://sub.другой-провайдер.ru/токен_клиента"}'

# Бан
curl -X POST "https://whitelisthub.net/api/v1/key/ban" \
  -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
  -d '{"key":"KEY_ID","message":"Заблокировано"}'

# Разбан
curl -X POST "https://whitelisthub.net/api/v1/key/ban" \
  -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
  -d '{"key":"KEY_ID","unblock":true}'

# Удаление
curl -X POST "https://whitelisthub.net/api/v1/key/delete" \
  -H "Authorization: Bearer TOKEN" -H "Content-Type: application/json" \
  -d '{"key":"KEY_ID"}'

Автосохранение настроек подписки

В панели → Подписка при изменении поля отправляется только изменённое поле (JSON patch), заголовок X-Sub-Autosave-Patch: 1. Это снижает нагрузку при частом редактировании announce / Happ meta.

Коды ошибок

errorHTTP
Unauthorized401
key_not_found404
insufficient_balance400
invalid_limit400
idempotency_in_progress409
idempotency_key_mismatch422
no_fields400

Bedolaga bridge (webhook)

Интеграция для реселлеров с Bedolaga: после оплаты в боте webhook создаёт ключ в Traff.

Настройка: панель → Bedolaga (личный кабинет).

POST /bedolaga/hook/{webhook_token}

Публичный endpoint (без Bearer). Token уникален для tenant.

Заголовки от Bedolaga:

  • X-Webhook-Event — например payment.completed
  • X-Webhook-Signaturesha256=… (HMAC-SHA256 body, если задан secret)

Ответ (успех):

json
{
  "success": true,
  "action": "created",
  "key_id": "Ro3WcRCM0oT95XhY",
  "subscription_url": "https://sub.example.ru/sub/Ro3WcRCM0oT95XhY",
  "limit_gb": 50,
  "months": 1,
  "bedolaga_user_id": "501"
}

При повторной доставке того же события: "idempotent_replay": true.

GET /bedolaga/hook/{webhook_token}

Health-check ({"status":"ok","service":"traff_bedolaga_bridge"}).

GET /bedolaga/link

Поиск связи Bedolaga → Traff (Bearer token).

Query: bedolaga_user_id, telegram_id, subscription_id, key.

GET /bedolaga/links

Последние связи tenant (Bearer token).

POST /bedolaga/public/subscription/{webhook_token}

Публичный API для Mini App «Подключиться» (без Bearer). Token = webhook token tenant.

Body (JSON):

json
{
  "init_data": "query_string из Telegram.WebApp.initData"
}

Опционально (только если в панели включён insecure fallback и нет bot token):

json
{ "telegram_id": "123456789" }

Ответ (успех):

json
{
  "success": true,
  "subscription_url": "https://sub.example.ru/sub/KEY",
  "key_id": "Ro3WcRCM0oT95XhY",
  "brand": "MyVPN"
}

Ошибки: invalid_init_data (401), subscription_not_ready (404), connect_disabled (400).

GET /bedolaga/connect/{webhook_token}

HTML-страница Mini App: загружает подписку через public API, копирование URL, deep link Happ.

Настройка Bedolaga: CONNECT_BUTTON_MODE=miniapp_custom, MINIAPP_CUSTOM_URL = этот URL.

Плагин и инструкция: панель → Bedolaga → «Инструкция установки», файлы в integrations/bedolaga/.

Нужен API token?

Зарегистрируйтесь на лендинге — trial 1 GB, token в разделе «API» после входа.

Регистрация партнёра
✓ Скопировано