{
  "info": {
    "name": "VPN Reseller API",
    "description": "Документация: https://hexpartners.pro/api/vpn/docs",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.relayhub.surf"
    },
    {
      "key": "api_key",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Тарифы",
      "item": [
        {
          "name": "Тарифы и цены",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/plans",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "plans"
              ]
            },
            "description": "Активные тарифы с ценой, которую спишем с вашего депозита за покупку или\nпродление. Пробный тариф в `trial` (если включён в кабинете), пакеты трафика в\n`traffic_packs`. Цены в USD и меняются редко, но кэшировать их дольше часа не стоит."
          }
        }
      ]
    },
    {
      "name": "Депозит",
      "item": [
        {
          "name": "Баланс депозита",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/balance",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "balance"
              ]
            },
            "description": "Сколько можно потратить прямо сейчас.\n\n`spendable` = `paid` (внесено пополнениями, не выводится) + `earned`\n(заработано на продажах в ботах, выводится). Покупки через API списываются\nсначала с `paid`, потом с `earned`."
          }
        }
      ]
    },
    {
      "name": "Подписки",
      "item": [
        {
          "name": "Список подписок",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions"
              ],
              "query": [
                {
                  "key": "external_user_id",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "telegram_id",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "plan_uuid",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "product",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "is_trial",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "updated_since",
                  "value": "2026-10-14T00:00:00Z",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "offset",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Все подписки аккаунта, включая проданные через ботов. Без живого трафика: он есть\nтолько в карточке одной подписки.\n\nОбычный режим: новые сверху, страницы по `offset`. Режим синхронизации (задан\n`updated_since` или `cursor`): по возрастанию `updated_at`, в ответе `next_cursor`,\nлистайте, пока он не `null`, и запомните `updated_at` последней подписки для\nследующего захода. Подходит, чтобы держать свою базу в актуальном виде без запроса\nна каждую подписку."
          }
        },
        {
          "name": "Купить подписку",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions"
              ]
            },
            "description": "Списывает цену тарифа с депозита и выдаёт подписку. В ответе `subscription_url`:\nеё вы отдаёте пользователю, он вставляет ссылку в VPN-клиент.\n\nОдин `external_user_id` может иметь несколько подписок. Повтор с тем же `custom_id`\nвернёт ту же подписку с `idempotent_replay: true`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_user_id\": \"user-42\",\n  \"custom_id\": \"{{$guid}}\",\n  \"plan_uuid\": \"550e8400-e29b-41d4-a716-446655440000\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Выдать пробный период",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/trial",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                "trial"
              ]
            },
            "description": "Бесплатно, один раз на `external_user_id`. Работает, если пробный период включён в\nкабинете. Пробную подписку нельзя продлить и заморозить, только перевести на платный\nтариф апгрейдом.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_user_id\": \"user-42\",\n  \"custom_id\": \"{{$guid}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Статус подписки",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Карточка с остатком дней, израсходованным трафиком (`traffic_used_bytes`,\n`null` если поставщик не ответил), живым лимитом `traffic_limit_bytes` и моментом,\nна который верен расход (`usage_updated_at`): цифры кэшируются до минуты."
          }
        },
        {
          "name": "Продлить на период тарифа",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/renew",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "renew"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Добавляет полный период тарифа по текущей цене из GET /plans. Истёкшая подписка\nвозобновляется с текущего момента, действующая получает дни к концу срока.\nЗамороженную сначала разморозьте.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Продлить на N дней",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/renew-custom",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "renew-custom"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Цена и трафик считаются пропорционально тарифу: `price / plan_days × days`,\nокругление вверх до цента.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\",\n  \"days\": 45\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Сколько стоит апгрейд",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/upgrade-quote",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "upgrade-quote"
              ],
              "query": [
                {
                  "key": "new_plan_uuid",
                  "value": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Доплата за переход: полная цена нового тарифа минус неиспользованный остаток\nтекущего. Апгрейд перезапускает срок с текущего момента."
          }
        },
        {
          "name": "Сколько стоит продление",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/renew-quote",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "renew-quote"
              ],
              "query": [
                {
                  "key": "days",
                  "value": "45",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Цена продления без списания: столько спишут `renew` (без `days`) или\n`renew-custom` (с `days`) прямо сейчас. Передайте её в `max_charge_minor`, чтобы\nпродление не прошло дороже показанного покупателю."
          }
        },
        {
          "name": "Сменить тариф",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/upgrade",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "upgrade"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Списывает доплату из upgrade-quote и переводит подписку на новый тариф.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\",\n  \"new_plan_uuid\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Докупить трафик (белые списки)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/traffic",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "traffic"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Трафик для серверов обхода белых списков, для подписки любого вида. Объём `gb`:\nподписке на срок из `traffic_packs`, подписке «Навсегда» из `lifetime.traffic_packs`\n(GET /plans). Лимит растёт сразу, у «Навсегда» купленный трафик не сгорает.\nВебхук: у подписки на срок `subscription.traffic_purchased`, у «Навсегда»\n`subscription.addon_purchased` с `addon_id`. К пробной подписке на срок трафик\nне докупается: 409 `trial_no_traffic`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\",\n  \"gb\": 10\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Докупка к бессрочной (трафик, устройства)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/addons",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "addons"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Трафик для лимитных серверов или +15 устройств к подписке «Навсегда». Варианты и\nцены в `lifetime.addons` (GET /plans). Купленный трафик не сгорает и прибавляется к\nостатку. Подписке на срок трафик докупается через `/traffic`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\",\n  \"addon_id\": \"gb_200\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Заморозить",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/freeze",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "freeze"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Срок останавливается, конфиг не отдаётся. Повтор по уже замороженной вернёт\n409 `subscription_state`."
          }
        },
        {
          "name": "Обновить ссылку",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/rotate-link",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "rotate-link"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Выдаёт подписке новый адрес. Старая ссылка перестаёт отдавать конфиг сразу,\nновая в `subscription_url`: отдайте её пользователю заново. Нужно, когда ссылка\nутекла.\n\nУстройства, которые уже импортировали профиль, продолжат подключаться: ключи\nсерверов при обновлении не меняются. Чтобы закрыть доступ полностью, заморозьте\nподписку.\n\nНе чаще раза в час на подписку, иначе 409 `subscription_state`."
          }
        },
        {
          "name": "Разморозить",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/unfreeze",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "unfreeze"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Срок продолжается с того места, где был остановлен. Новый `end_date` в ответе."
          }
        }
      ]
    },
    {
      "name": "Пользователи",
      "item": [
        {
          "name": "Привязать пользователя из бота",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/clients/link",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "clients",
                "link"
              ]
            },
            "description": "Связывает ваш `external_user_id` с человеком из вашего бота по `telegram_id`, без\nпокупки. После этого его подписки, купленные в боте, находятся по\n`external_user_id` и управляются через API.\n\n`result`: `linked` (привязали), `already_linked` (уже было так, повтор безопасен),\n`created` (человека с таким Telegram у вас ещё не было: заведён, и бот увидит его,\nкогда он придёт). 409 `external_user_conflict` с полем `conflict`: `telegram_taken`\n(этот Telegram уже под другим `external_user_id`, он в поле `external_user_id`) или\n`external_id_taken` (ваш `external_user_id` уже у другого человека).",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"external_user_id\": \"user-42\",\n  \"telegram_id\": 123456789\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Привязать пользователей пачкой",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/clients/link/batch",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "clients",
                "link",
                "batch"
              ]
            },
            "description": "То же, что `POST /clients/link`, до 1000 строк за раз: перенести базу бота одним\nвызовом. Строки независимы: конфликт одной не отменяет остальные, ответ по каждой в\nтом же порядке (`result` или `error_code` с `error`). Повтор всего пакета безопасен."
          }
        },
        {
          "name": "Найти пользователей",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/clients",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "clients"
              ],
              "query": [
                {
                  "key": "telegram_id",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "external_user_id",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "linked",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "offset",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Пользователи аккаунта, новые сверху, у каждого до 20 последних подписок (полный\nсписок в `GET /subscriptions?external_user_id=…`). Сюда попадают и люди из ботов, и\nзаведённые через API."
          }
        }
      ]
    },
    {
      "name": "Устройства",
      "item": [
        {
          "name": "Устройства подписки",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/devices",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "devices"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Устройства, подключавшие конфиг, у подписки любого вида, и на срок, и «Навсегда».\nЛимит задаёт тариф (`devices` в подписке). `last_seen` у «Навсегда» это последнее\nобновление конфига устройством."
          }
        },
        {
          "name": "Удалить устройство",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/devices/:device_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "devices",
                ":device_id"
              ],
              "query": [
                {
                  "key": "block",
                  "value": "",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                },
                {
                  "key": "device_id",
                  "value": "7",
                  "description": "Номер устройства: `id` из `GET /subscriptions/{id}/devices`."
                }
              ]
            },
            "description": "Освобождает слот. По умолчанию ещё и отключает устройство: переустановка\nVPN-клиента не помогает, идентификатор устройства остаётся тем же. Вернуть его\nможно через `DELETE /subscriptions/{id}/devices/blocked/{block_id}`."
          }
        },
        {
          "name": "Отключённые устройства",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/devices/blocked",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "devices",
                "blocked"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                }
              ]
            },
            "description": "Устройства, удалённые с отключением: по этой ссылке они конфиг не получают."
          }
        },
        {
          "name": "Вернуть отключённое устройство",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/subscriptions/:subscription_id/devices/blocked/:block_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "subscriptions",
                ":subscription_id",
                "devices",
                "blocked",
                ":block_id"
              ],
              "variable": [
                {
                  "key": "subscription_id",
                  "value": "01a06315-1270-705a-8d4c-58fea607bf2c",
                  "description": "Идентификатор подписки: `subscription.subscription_id` из ответа покупки или списка."
                },
                {
                  "key": "block_id",
                  "value": "01a10bb4-3455-7a54-b46a-886c3f61f723",
                  "description": "Отключённое устройство: `block_id` из `GET /subscriptions/{id}/devices/blocked`."
                }
              ]
            },
            "description": "Снимает отключение: при следующем обновлении подписки в VPN-клиенте устройство\nподключится заново и займёт слот, если он свободен. Ссылка не меняется."
          }
        }
      ]
    },
    {
      "name": "Операции",
      "item": [
        {
          "name": "Результат операции",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/operations/:custom_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "operations",
                ":custom_id"
              ],
              "variable": [
                {
                  "key": "custom_id",
                  "value": "11111111-1111-4111-8111-111111111111",
                  "description": "Ваш custom_id операции."
                }
              ]
            },
            "description": "Что стало с денежной операцией: `in_progress` (ещё выполняется), `done` (готово,\nответ в `result`) или `failed` (отказ, тело в `error`, тот же `custom_id` можно\nповторить). Ничего не меняет и денег не списывает: годится для восстановления после\nпотерянного ответа или перезапуска вашего сервера. 404 `operation_not_found` значит,\nчто запрос до нас не дошёл."
          }
        }
      ]
    },
    {
      "name": "Пополнение",
      "item": [
        {
          "name": "Способы пополнения",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/deposit/providers",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "deposit",
                "providers"
              ]
            },
            "description": "Провайдеры, доступные прямо сейчас. Набор зависит от настроек площадки."
          }
        },
        {
          "name": "Выставить счёт на пополнение",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/deposit",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "deposit"
              ]
            },
            "description": "Возвращает `invoice_url`: откройте его сами или отдайте бухгалтеру. Зачисление\nприходит вебхуком `deposit.credited` и видно в GET /deposit/{custom_id}.\n\nПовтор с тем же `custom_id` и другой суммой или провайдером отбивается 409: для\nденег тихий повтор со старой суммой опаснее ошибки.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"custom_id\": \"{{$guid}}\",\n  \"provider\": \"cryptobot\",\n  \"amount_minor\": 1000\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Статус пополнения",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/deposit/:custom_id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "deposit",
                ":custom_id"
              ],
              "variable": [
                {
                  "key": "custom_id",
                  "value": "11111111-1111-4111-8111-111111111111",
                  "description": "Ваш `custom_id`, с которым выставлялся счёт."
                }
              ]
            },
            "description": ""
          }
        },
        {
          "name": "История пополнений",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/deposits",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "deposits"
              ],
              "query": [
                {
                  "key": "offset",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": ""
          }
        }
      ]
    },
    {
      "name": "Вебхуки",
      "item": [
        {
          "name": "Настройки вебхука",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/webhook",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "webhook"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Задать адрес и события",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/webhook",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "webhook"
              ]
            },
            "description": "Секрет подписи возьмите в кабинете (раздел «Ключ и вебхук»). Проверяйте подпись:\n`X-Signature: sha256=hex(HMAC-SHA256(secret, raw_body))`, сравнение\nconstant-time по сырым байтам тела до разбора JSON."
          }
        },
        {
          "name": "Тестовая отправка",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/webhook/test",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "webhook",
                "test"
              ]
            },
            "description": "Шлёт событие `webhook.test` на ваш адрес прямо сейчас и возвращает, что\nответил сервер. Одна попытка, без ретраев."
          }
        },
        {
          "name": "Лента событий",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/events",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "events"
              ],
              "query": [
                {
                  "key": "since",
                  "value": "2026-10-14T00:00:00Z",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "События, которые готовились вашему вебхуку, в порядке появления: чтобы догнать\nпропущенное после сбоя вашего сервера, не дожидаясь повторов. В `payload` ровно то\nтело, что уходит вебхуком, рядом статус его доставки. Листайте по `next_cursor`, пока\nон не `null`. Хранятся 30 дней; событий нет, если вебхук не задан."
          }
        },
        {
          "name": "Журнал доставок",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/webhook/deliveries",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "webhook",
                "deliveries"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "event",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "offset",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Попытки доставки вебхуков, новые сверху: статус, что ответил ваш сервер, сколько\nшло. То же, что раздел «Доставки вебхуков» в кабинете."
          }
        },
        {
          "name": "Отправить событие заново",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/api/v1/vpn/webhook/deliveries/:delivery_id/redeliver",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "vpn",
                "webhook",
                "deliveries",
                ":delivery_id",
                "redeliver"
              ],
              "variable": [
                {
                  "key": "delivery_id",
                  "value": "01a06321-0000-7000-8000-000000000002",
                  "description": "Доставка: `delivery_id` из `GET /webhook/deliveries` или `event_id` из ленты событий."
                }
              ]
            },
            "description": "Повторяет доставку прямо сейчас тем же телом (новая метка времени и подпись) и\nвозвращает, что ответил ваш сервер. Одна попытка, счётчик неудач адреса не растёт.\nНе больше 10 ручных отправок в минуту вместе с тестовой."
          }
        }
      ]
    }
  ]
}
