Ваш сайт или программа сама выдаёт подписки из нашего VPN. Нужен разработчик.

Купить подписку

POST/api/v1/vpn/subscriptions

Списывает цену тарифа с депозита и выдаёт подписку. В ответе subscription_url: её вы отдаёте пользователю, он вставляет ссылку в VPN-клиент. Один external_user_id может иметь несколько подписок. Повтор с тем же custom_id вернёт ту же подписку с idempotent_replay: true.

Тело запроса

external_user_idstringобязательно

Идентификатор пользователя в вашей системе. Один человек = один id.

telegram_idinteger | nullнеобязательно

Telegram id пользователя. Если задан, подписка появится у него в мини-аппе вашего бота (укажите bot_id) и он получит уведомления бота.

bot_iduuid | nullнеобязательно

UUID вашего бота (кабинет, «Ключ и вебхук», «Ваши боты»). Нужен вместе с telegram_id, чтобы подписка появилась в мини-приложении бота.

custom_idstringобязательно

Ваш идентификатор операции, уникальный в рамках аккаунта. Повтор запроса с тем же custom_id вернёт результат первой попытки без повторного списания.

plan_uuiduuidобязательно

Тариф из GET /plans.

max_charge_minorinteger | nullнеобязательно

Необязательно. Сколько центов вы готовы списать. Если цена операции выше, она не выполняется и отвечает 409 max_charge_exceeded, деньги не списаны. Передайте сумму, которую показали покупателю.

Когда откажет

401unauthorized: Неверный или отсутствующий API-ключ
402insufficient_balance: Недостаточно средств на депозите
403forbidden: Объект принадлежит другому аккаунту; api_disabled: Доступ к API для этого аккаунта закрыт; ip_not_allowed: Адрес запроса не входит в список разрешённых
404plan_not_found: Тариф не найден или недоступен
409max_charge_exceeded: Цена операции выше max_charge_minor; custom_id_conflict: Этот custom_id уже использован с другими параметрами; operation_in_progress: Операция с этим custom_id ещё выполняется; external_user_conflict: telegram_id или external_user_id уже привязан к другому пользователю
422validation_error: Неверные параметры запроса
429rate_limited: Слишком много запросов
503upstream_unavailable: Поставщик VPN временно недоступен
Попробовать запрос

Подставится в примеры и в запрос. Хранится только в этом браузере.

curl -X POST https://api.relayhub.surf/api/v1/vpn/subscriptions \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "external_user_id": "user-42",
    "custom_id": "11111111-1111-4111-8111-111111111111",
    "plan_uuid": "550e8400-e29b-41d4-a716-446655440000"
  }'
Вставьте свой ключ, и он подставится вместо <YOUR_API_KEY>.

Запрос меняет данные или списывает деньги: выполняйте его из своего кода.

Пример ответа
{
  "success": true,
  "custom_id": "11111111-1111-4111-8111-111111111111",
  "subscription": {
    "subscription_id": "01a06315-1270-705a-8d4c-58fea607bf2c",
    "client_id": "01a06310-8f2b-7c11-9a3e-2b5c7d9e1f00",
    "external_user_id": "user-42",
    "telegram_id": null,
    "bot_id": null,
    "source": "api",
    "plan_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "plan_name": "Standard 30d",
    "is_trial": false,
    "product": "term",
    "is_lifetime": false,
    "status": "active",
    "subscription_url": "https://api.relayhub.surf/sub/wnT9NRf0Zk6McRRnp2nggc3K",
    "days": 30,
    "days_left": 30,
    "devices": 2,
    "traffic_limit_bytes": null,
    "auto_renew": false,
    "renewal_count": 0,
    "renewal_progress": 0,
    "created_at": "2026-09-02T12:00:00Z",
    "end_date": "2026-10-02T12:00:00Z",
    "frozen_at": null,
    "price_minor": 450,
    "price_usd": "4.50"
  },
  "charged_minor": 450,
  "charged_usd": "4.50",
  "balance_after_minor": 11600,
  "balance_after_usd": "116.00"
}

Поля ответа

successboolean

true у любого успешного ответа.

custom_idstring

Ваш custom_id операции, как в запросе.

subscriptionobject

Подписка после операции.

charged_minorinteger

Сколько списано с депозита за эту операцию, в центах.

charged_usdstring

То же, строкой для показа.

balance_after_minorinteger

Сколько осталось потратить (spendable) после списания, в центах.

balance_after_usdstring

То же, строкой для показа.

idempotent_replayboolean

Есть только в ответе на повтор с тем же custom_id: true, это результат первой попытки, деньги второй раз не списаны.

Собираем анонимную аналитику посещений. Подробнее