Конструктор подписок
Методы для управления пользовательскими подписками: создание, изменение, удаление.
Обзор
Модуль для работы с пользовательскими подписками. Базовый путь: /profile/custom-subscriptions. Доступны методы GET/POST/PATCH/PUT/DELETE. Позволяет собирать собственные подписки из конфигов/платных опций, управлять устройствами, настройками отображения, маршрутизацией и Xray JSON-режимом.
Общие схемы раздела
CustomSubscriptionData:{ id, title, subscription_key (расшифрован), items_count }.CustomSubscriptionDetailData:CustomSubscriptionData+items: CustomSubscriptionItemData[].CustomSubscriptionItemData:{ id, item_type, item_reference_id, item_index?, position, resolved_title, is_valid, server_config? }.CustomSubscriptionItemBody(используется при создании/замене items):item_type(@IsIn(['user_config','cloud_server_config','paid_option','paid_option_index','paid_option_config'])),item_reference_id(@IsInt@Min(1)),item_index?(@IsInt@Min(0)@Max(20)).
GET /profile/custom-subscriptions
Получить список пользовательских подписок (сортировка по created_at DESC).
Rate Limit: глобальный (60 req/min)
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: Array<{
id: number
title: string
subscription_key: string
items_count: number
}>
}GET /profile/custom-subscriptions/available-items
Получить доступные элементы для создания подписки.
Rate Limit: глобальный (60 req/min)
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/available-items" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
configs: Array<{
id: number
title: string
location_emoji?: string
expires_at: number
is_online: boolean
source: "user_config" | "cloud_server_config"
cloud_server_id?: number // только для source: "cloud_server_config"
}>
paid_options: Array<{
id: number
title: string
expires_at: number
configs: Array<{
type: "index"
users_paid_option_id: number
expires_at: number
index: number
original_title: string
custom_title: string | null
is_online: boolean
} | {
type: "server"
users_paid_option_id: number
expires_at: number
id: number
server_id: number
title: string // Пользовательское название конфига
resolved_title: string // Итоговое отображаемое название
is_online: boolean
}>
}>
}
}Конфиги с протоколом amnezia-wg исключены из выдачи.
GET /profile/custom-subscriptions/:id
Получить детали пользовательской подписки (items по position ASC).
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
id: number
title: string
subscription_key: string
items_count: number
items: Array<{
id: number
item_type: string
item_reference_id: number
item_index: number | null
position: number
resolved_title: string | null
is_valid: boolean
server_config: {
id: number
server_id: number
location_id: number
title: string
protocol: string
} | null
}>
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
POST /profile/custom-subscriptions
Создать пользовательскую подписку.
Rate Limit: 3 req / 5 sec
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Да | Название (1-64 символа) |
items | Array | Да | Элементы подписки (1-50) |
items[].item_type | string | Да | user_config | cloud_server_config | paid_option | paid_option_index | paid_option_config |
items[].item_reference_id | number | Да | ID элемента |
items[].item_index | number | Нет | Индекс для paid_option_index (0-20) |
Пример запроса
curl -X POST "https://api.stealthsurf.net/profile/custom-subscriptions" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"title": "Моя подписка",
"items": [
{ "item_type": "user_config", "item_reference_id": 123 },
{ "item_type": "paid_option_index", "item_reference_id": 456, "item_index": 0 }
]
}'Ответ
{
status: true,
statusCode: 201,
data: {
id: number
title: string
subscription_key: string
items_count: number
items: Array<{
id: number
item_type: string
item_reference_id: number
item_index: number | null
position: number
resolved_title: string | null
is_valid: boolean
server_config: {
id: number
server_id: number
location_id: number
title: string
protocol: string
} | null
}>
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 28 | custom subscription limit reached | У пользователя уже 25 кастомных подписок |
| 3 | bad request | Передано больше 50 элементов |
| 30 | custom subscription invalid item | Элемент не принадлежит пользователю, истёк срок его действия либо item_index выходит за пределы доступных конфигов |
PATCH /profile/custom-subscriptions/:id/title
Обновить название подписки.
Rate Limit: 5 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Да | Новое название (1-64 символа) |
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/title" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"title": "Новое название"
}'Ответ
{
status: true,
statusCode: 200,
data: {
id: number
title: string
subscription_key: string
items_count: number
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PUT /profile/custom-subscriptions/:id/items
Заменить элементы подписки.
Rate Limit: 3 req / 2 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
items | Array | Да | Новые элементы (заменяют существующие, 1-50) |
items[].item_type | string | Да | user_config | cloud_server_config | paid_option | paid_option_index | paid_option_config |
items[].item_reference_id | number | Да | ID элемента |
items[].item_index | number | Нет | Индекс для paid_option_index (0-20) |
Пример запроса
curl -X PUT "https://api.stealthsurf.net/profile/custom-subscriptions/123/items" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "item_type": "user_config", "item_reference_id": 789 }
]
}'Ответ
{
status: true,
statusCode: 200,
data: {
id: number
title: string
subscription_key: string
items_count: number
items: Array<{
id: number
item_type: string
item_reference_id: number
item_index: number | null
position: number
resolved_title: string | null
is_valid: boolean
server_config: {
id: number
server_id: number
location_id: number
title: string
protocol: string
} | null
}>
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 3 | bad request | Передано больше 50 элементов |
| 30 | custom subscription invalid item | Элемент не принадлежит пользователю, истёк срок его действия либо item_index выходит за пределы доступных конфигов |
PATCH /profile/custom-subscriptions/:id/items/order
Изменить порядок элементов подписки.
Rate Limit: 5 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
item_ids | number[] | Да | ID элементов в нужном порядке (1-50, ровно существующие ID, без дубликатов) |
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/items/order" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"item_ids": [3, 1, 2]
}'Ответ
{
status: true,
statusCode: 200,
data: {
id: number
title: string
subscription_key: string
items_count: number
items: Array<{
id: number
item_type: string
item_reference_id: number
item_index: number | null
position: number
resolved_title: string | null
is_valid: boolean
server_config: {
id: number
server_id: number
location_id: number
title: string
protocol: string
} | null
}>
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 3 | bad request | Набор item_ids не совпадает с текущими элементами подписки или содержит дубликаты |
POST /profile/custom-subscriptions/:id/reset-key
Переиздать ключ подписки.
Rate Limit: 2 req / 10 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X POST "https://api.stealthsurf.net/profile/custom-subscriptions/123/reset-key" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
id: number
title: string
subscription_key: string // Новый ключ
items_count: number
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
После переиздания ключа старый ключ перестанет работать. Убедитесь, что обновили ключ во всех приложениях.
POST /profile/custom-subscriptions/:id/share/vk-document
Поделиться подпиской через VK-документ: конфиги выгружаются в текстовый документ, в ответе возвращается прямая ссылка на него.
Rate Limit: 2 req / 10 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X POST "https://api.stealthsurf.net/profile/custom-subscriptions/123/share/vk-document" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
url: string // Прямая ссылка на VK-документ
expires_at: number // Unix timestamp истечения ссылки
ttl: number // Время жизни ссылки в секундах
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 3 | bad request | Не удалось расшифровать ключ подписки |
| 90 | vk share failed | Подписка не содержит конфигов либо загрузка документа в VK не удалась |
DELETE /profile/custom-subscriptions/:id
Удалить подписку вместе с её элементами и привязанными устройствами.
Rate Limit: 3 req / 2 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X DELETE "https://api.stealthsurf.net/profile/custom-subscriptions/123" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
GET /profile/custom-subscriptions/:id/encrypted-subscription-link
Получить зашифрованные ссылки на подписку для клиентов Happ и INCY.
Rate Limit: 3 req / 60 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/encrypted-subscription-link" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
happ: string // Ссылка вида happ://crypt4/...
incy: string // Ссылка вида incy://crypt1/...
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 3 | bad request | Не удалось расшифровать ключ подписки |
Настройки отображения подписки
Методы для управления настройками отображения кастомной подписки в приложениях (заголовок профиля, объявление, ссылки, кастомные заголовки ответа).
GET /profile/custom-subscriptions/:id/display/settings
Получить настройки отображения подписки.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/display/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
profile_title: string | null
announce: string | null
announce_url: string | null
support_url: string | null
profile_web_page_url: string | null
custom_headers: Array<{
name: string
value: string
}> | null
profile_update_interval: number // по умолчанию 12 (часы)
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PATCH /profile/custom-subscriptions/:id/display/settings
Обновить настройки отображения подписки. Передаются только изменяемые поля, остальные сохраняются.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
profile_title | string | Нет | Заголовок профиля (MaxLength 25) |
announce | string | Нет | Текст объявления с разметкой цвета {#HEX}текст{/} (MaxLength 200) |
announce_url | string | Нет | Ссылка объявления (валидный URL) |
support_url | string | Нет | Ссылка поддержки (валидный URL) |
profile_web_page_url | string | Нет | Ссылка на веб-страницу профиля (валидный URL) |
custom_headers | object[] | null | Нет | Кастомные заголовки ответа при отдаче подписки (макс. 20), null очищает список. Каждый: name (string, 1-64), value (string, MaxLength 1024). Нормализуются на сервере (имена в нижнем регистре, проверка blacklist, без дубликатов, суммарный размер имён и значений не более 8192 символов) |
profile_update_interval | number | Нет | Интервал автообновления, ч (@IsInt, @Min(1), @Max(12)) |
Имя заголовка должно соответствовать регулярному выражению:
/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/Запрещены служебные заголовки (cookie, authorization, content-type, host, announce, profile-title и т. п.), а также имена, начинающиеся с access-control-, x-accel-, x-sendfile, x-forwarded-, cross-origin-.
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/display/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"profile_title": "My VPN",
"announce": "ℹ️ {#2181CD}Update{/} subscription",
"support_url": "https://t.me/my_support",
"custom_headers": [
{ "name": "x-subscription-owner", "value": "family" }
]
}'Ответ
Такой же как GET /profile/custom-subscriptions/:id/display/settings.
Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 3 | bad request | Некорректные custom_headers: не массив, больше 20 элементов, пустое или слишком длинное имя, недопустимые символы, дубликат имени, запрещённый заголовок либо превышение суммарного размера 8192 символа |
XRay шаблон подписки
Методы для управления XRay шаблоном (JSON mode) кастомной подписки.
GET /profile/custom-subscriptions/:id/xray-template/settings
Получить настройки XRay JSON mode для подписки.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/xray-template/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
json_mode: boolean
json_default_config_tag: string | null // устарело
fragment: boolean
auto_select_enabled: boolean
auto_select_name: string | null
global_quick_toggles: {
ruDirect: boolean
androidAutoDirect: boolean
ruWhitelistDirect: boolean
lanDirect: boolean
bittorrentDirect: boolean
blockQuic: boolean
blockAds: boolean
gameDownloadsDirect: boolean
blockPorn: boolean
}
custom_auto_selects: Array<{
id: number
name: string
strategy: "leastPing" | "leastLoad" | "random" | "roundRobin"
config_tags: string[]
}>
global_routing_rules: object[] // Глобальные правила маршрутизации XRay
dns: {
resolve_direct_ipv4: boolean // Главный выключатель клиентского DNS-блока
dns_preset?: string // Пресет DoH-резолвера
custom_dns_url?: string // Пользовательский DoH URL при dns_preset: "custom"
}
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PATCH /profile/custom-subscriptions/:id/xray-template/settings
Обновить настройки XRay JSON mode для подписки. При выключении json_mode сбрасываются fragment, авто-выбор, быстрые переключатели, DNS-блок, пользовательские балансировщики и сохранённый XRay-шаблон подписки.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
json_mode | boolean | Нет | Включить JSON mode для подписки |
json_default_config_tag | string | Нет | (Устарело) Тег исходящего по умолчанию. Формат ^(config|cloud|option|ext)-\d+$ |
fragment | boolean | Нет | Включить TLS-фрагмент (обход DPI) |
auto_select_enabled | boolean | Нет | Включить виртуальный конфиг авто-выбора с балансировщиком leastPing |
auto_select_name | string | Нет | Отображаемое имя конфига авто-выбора (MaxLength 128) |
global_quick_toggles | object | Нет | Частичное слияние. Допустимые ключи: ruDirect, androidAutoDirect, ruWhitelistDirect, lanDirect, bittorrentDirect, blockQuic, blockAds, gameDownloadsDirect, blockPorn. Каждое значение — boolean |
custom_auto_selects | object[] | Нет | Набор авто-выборов (заменяет существующие). @ArrayMaxSize(10), @ValidateNested({each}) |
global_routing_rules | unknown[] | Нет | Полная замена глобальных правил маршрутизации XRay (макс. 100) |
dns | object | Нет | Блок клиентского DNS (частичное обновление) |
CustomAutoSelectBody: id? (@IsInt, @Min(1); для новых записей не указывается и назначается сервером), name (@Length(1,64)), strategy? (@IsIn(['leastPing','leastLoad','random','roundRobin']), по умолчанию leastPing), config_tags (@ArrayMinSize(2) @ArrayMaxSize(50), формат config-N/option-N/cloud-N/ext:N:M). Все поля тела необязательны.
DnsSettingsBody:
| Field | Type | Required | Description |
|---|---|---|---|
resolve_direct_ipv4 | boolean | Нет | Резолвить прямой (не-VPN) трафик по IPv4; главный выключатель клиентского DNS-блока |
dns_preset | string | Нет | Пресет DoH-резолвера: cloudflare, google, quad9, adguard, adguard_family, yandex, comss, mullvad или custom |
custom_dns_url | string | Нет | Пользовательский DoH URL (только https), обязателен при dns_preset: "custom" |
Правила для global_routing_rules: каждое правило — объект с type: "field"; допустимые поля type, domain, ip, protocol, port, network, outboundTag; outboundTag обязателен и может быть только direct, block или proxy; должно присутствовать хотя бы одно условие (domain, ip, protocol либо port/network); protocol — из набора http, tls, quic, bittorrent; network — tcp, udp или tcp,udp.
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/xray-template/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"json_mode": true,
"fragment": false,
"global_quick_toggles": {
"ruDirect": true
}
}'Ответ
{
status: true,
statusCode: 200,
data: {
json_mode: boolean
json_default_config_tag: string | null // устарело
fragment: boolean
auto_select_enabled: boolean
auto_select_name: string | null
global_quick_toggles: {
ruDirect: boolean
androidAutoDirect: boolean
ruWhitelistDirect: boolean
lanDirect: boolean
bittorrentDirect: boolean
blockQuic: boolean
blockAds: boolean
gameDownloadsDirect: boolean
blockPorn: boolean
}
custom_auto_selects: Array<{
id: number
name: string
strategy: "leastPing" | "leastLoad" | "random" | "roundRobin"
config_tags: string[]
}>
global_routing_rules: object[] // Глобальные правила маршрутизации XRay
dns: {
resolve_direct_ipv4: boolean // Главный выключатель клиентского DNS-блока
dns_preset?: string // Пресет DoH-резолвера
custom_dns_url?: string // Пользовательский DoH URL при dns_preset: "custom"
}
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 75 | no xray-compatible configs available for json mode | Включение json_mode, когда в подписке нет конфигов, совместимых с XRay |
| 3 | bad request | В global_quick_toggles передан неизвестный ключ или не-boolean значение |
| 77 | invalid routing rules | Некорректные global_routing_rules: больше 100 правил, недопустимые поля, отсутствие условия или недопустимый outboundTag |
| 55 | invalid dns server | При dns_preset: "custom" не передан custom_dns_url или указан небезопасный хост |
GET /profile/custom-subscriptions/:id/xray-template (устарело)
Получить XRay шаблон подписки.
Эндпоинт устарел, используйте xray-template/settings.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/xray-template" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
template: string // XRay шаблон (JSON)
is_custom: boolean
created_at: number // Unix timestamp
updated_at: number // Unix timestamp
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PUT /profile/custom-subscriptions/:id/xray-template (устарело)
Сохранить XRay шаблон подписки.
Эндпоинт устарел, используйте xray-template/settings.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
template | string | Да | XRay JSON-шаблон (без outbounds, MaxLength 32768) |
Пример запроса
curl -X PUT "https://api.stealthsurf.net/profile/custom-subscriptions/123/xray-template" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"template": "{...}"
}'Ответ
{
status: true,
statusCode: 200,
data: {
template: string // XRay шаблон (JSON)
is_custom: boolean
created_at: number // Unix timestamp
updated_at: number // Unix timestamp
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 73 | xray template invalid | Неверный Xray-шаблон |
DELETE /profile/custom-subscriptions/:id/xray-template (устарело)
Сбросить XRay шаблон подписки к значениям по умолчанию.
Эндпоинт устарел, используйте xray-template/settings.
Rate Limit: 3 req / 2 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X DELETE "https://api.stealthsurf.net/profile/custom-subscriptions/123/xray-template" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
Устройства подписки
Методы для управления устройствами кастомной подписки.
GET /profile/custom-subscriptions/:id/devices
Получить список устройств подписки (по last_seen_at DESC).
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | Нет | Номер страницы (по умолчанию: 1) |
limit | number | Нет | Записей на странице (1-100, по умолчанию: 20) |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices?page=1&limit=20" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
devices: Array<{
id: number
title: string | null
device_name: string
device_type: string // ios, android, windows, macos, linux
device_model: string
os_version: string
is_blocked: boolean
is_approved: boolean // Подтверждено владельцем подписки
country: string | null
city: string | null
isp: string | null
last_seen_at: number // Unix timestamp
created_at: number // Unix timestamp
}>
total: number
page: number
limit: number
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
GET /profile/custom-subscriptions/:id/devices/settings
Получить настройки устройств подписки.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
block_unknown_devices: boolean
device_limit: number // 0 = безлимит
require_approval: boolean // Требовать подтверждение новых устройств
force_ipv6: boolean
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PATCH /profile/custom-subscriptions/:id/devices/settings
Обновить настройки устройств подписки. Передаются только изменяемые поля, остальные сохраняются.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
block_unknown_devices | boolean | Нет | Блокировать приложения без идентификатора устройства |
device_limit | number | Нет | Лимит устройств (0-100, 0 = безлимит) |
require_approval | boolean | Нет | Требовать подтверждение владельцем для каждого нового устройства. Новые устройства без hardware ID отклоняются, ранее подтверждённые продолжают работать |
force_ipv6 | boolean | Нет | Принудительно отдавать IPv6-адреса в подписке |
При включении block_unknown_devices (переход из false в true) все ранее записанные fingerprint-устройства подписки удаляются.
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/settings" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"block_unknown_devices": false,
"device_limit": 5
}'Ответ
Такой же как GET /profile/custom-subscriptions/:id/devices/settings.
Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
PATCH /profile/custom-subscriptions/:id/devices/:deviceId/title
Переименовать устройство.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
deviceId | number | Да | ID устройства |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Да | Название устройства (1-64 символа) |
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/456/title" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"title": "mom"
}'Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 40 | device not found | Устройство не найдено |
PATCH /profile/custom-subscriptions/:id/devices/:deviceId/blocked
Заблокировать или разблокировать устройство. При разблокировке устройство одновременно помечается подтверждённым.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
deviceId | number | Да | ID устройства |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
is_blocked | boolean | Да | Заблокировать (true) или разблокировать (false) устройство |
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/456/blocked" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"is_blocked": true
}'Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 40 | device not found | Устройство не найдено |
PATCH /profile/custom-subscriptions/:id/devices/:deviceId/approval
Подтвердить устройство, ожидающее одобрения: снимает блокировку и выставляет is_approved: true.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
deviceId | number | Да | ID устройства |
Пример запроса
curl -X PATCH "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/456/approval" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 40 | device not found | Устройство не найдено |
DELETE /profile/custom-subscriptions/:id/devices/:deviceId
Удалить устройство из подписки.
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
deviceId | number | Да | ID устройства |
Пример запроса
curl -X DELETE "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices/456" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
| 40 | device not found | Устройство не найдено |
DELETE /profile/custom-subscriptions/:id/devices
Удалить все устройства из подписки.
Rate Limit: 1 req / 2 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Пример запроса
curl -X DELETE "https://api.stealthsurf.net/profile/custom-subscriptions/123/devices" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
deleted_count: number // Количество удалённых устройств
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
Маршрутизация подписки
Методы для управления маршрутизацией (routing) и туннелями на уровне отдельных конфигов кастомной подписки.
GET /profile/custom-subscriptions/:id/routing/configs/:config_type/:config_reference_id
Получить настройки маршрутизации для конкретного конфига подписки. Если запись не сохранена, возвращаются пустые правила и эффективные значения, унаследованные от глобальных настроек.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
config_type | string | Да | Один из: user_config, paid_option_config, paid_option_index, cloud_server_config, auto_select |
config_reference_id | number | Да | ID конфига соответствующего типа (для auto_select — ID балансировщика из custom_auto_selects, 0 для встроенного) |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
config_index | number | Нет | Индекс конфига (по умолчанию: 0) |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/routing/configs/user_config/2?config_index=0" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: {
routing_rules: object[]
tunnels: Array<{
tag: string
source_config_type: string
source_config_id: number
source_config_index: number
source_config_label: string
}>
quick_toggle_overrides: object | null
effective_quick_toggles: {
ruDirect: boolean
androidAutoDirect: boolean
ruWhitelistDirect: boolean
lanDirect: boolean
bittorrentDirect: boolean
blockQuic: boolean
blockAds: boolean
gameDownloadsDirect: boolean
blockPorn: boolean
}
dns_overrides: object | null // null = наследуются глобальные настройки
effective_dns: {
resolve_direct_ipv4: boolean
dns_preset?: string
custom_dns_url?: string
}
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 3 | bad request | Недопустимый config_type |
| 27 | custom subscription not found | Подписка не найдена |
PUT /profile/custom-subscriptions/:id/routing/configs/:config_type/:config_reference_id
Сохранить настройки маршрутизации для конкретного конфига подписки (полная замена сохранённой записи).
Rate Limit: 3 req / 1 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
config_type | string | Да | Один из: user_config, paid_option_config, paid_option_index, cloud_server_config, auto_select |
config_reference_id | number | Да | ID конфига соответствующего типа (для auto_select — ID балансировщика из custom_auto_selects, 0 для встроенного) |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
config_index | number | Нет | Индекс конфига (по умолчанию: 0) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
routing_rules | unknown[] | Да | Массив правил маршрутизации XRay (макс. 100). Каждое правило: type: "field", обязательный outboundTag или balancerTag и поля только из набора type, domain, ip, port, sourcePort, network, source, user, inboundTag, protocol, attrs, outboundTag, balancerTag |
tunnels | object[] | Да | Массив туннелей (макс. 50). Для config_type: "auto_select" должен быть пустым |
tunnels[].tag | string | Да | Тег исходящего для этого туннеля. Не может быть direct, block, dns-out, fragment, proxy и не должен повторяться |
tunnels[].source_config_type | string | Да | Тип конфига-источника |
tunnels[].source_config_id | number | Да | ID конфига-источника |
tunnels[].source_config_index | number | Нет | Индекс конфига-источника (для paid_option_index) |
quick_toggle_overrides | object | null | Нет | Переопределения быстрых переключателей (null = наследовать глобальные). Допустимые ключи: ruDirect, androidAutoDirect, ruWhitelistDirect, lanDirect, bittorrentDirect, blockQuic, blockAds, gameDownloadsDirect, blockPorn; значения — boolean |
dns_overrides | object | null | Нет | Переопределение клиентского DNS для этого конфига (поля см. в DnsSettingsBody), null = наследовать глобальные |
Пример запроса
curl -X PUT "https://api.stealthsurf.net/profile/custom-subscriptions/123/routing/configs/user_config/2?config_index=0" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY" \
-H "Content-Type: application/json" \
-d '{
"routing_rules": [
{ "type": "field", "domain": ["geosite:google"], "outboundTag": "my-tunnel" }
],
"tunnels": [
{ "tag": "my-tunnel", "source_config_type": "user_config", "source_config_id": 2 }
],
"quick_toggle_overrides": null
}'Ответ
{
status: true,
statusCode: 200,
data: {
routing_rules: object[] // Сохранённые правила
tunnels: Array<{
tag: string
source_config_type: string
source_config_id: number
source_config_index: number
source_config_label: string
}>
quick_toggle_overrides: object | null
effective_quick_toggles: {
ruDirect: boolean
androidAutoDirect: boolean
ruWhitelistDirect: boolean
lanDirect: boolean
bittorrentDirect: boolean
blockQuic: boolean
blockAds: boolean
gameDownloadsDirect: boolean
blockPorn: boolean
}
dns_overrides: object | null // null = наследуются глобальные настройки
effective_dns: {
resolve_direct_ipv4: boolean
dns_preset?: string
custom_dns_url?: string
}
}
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 3 | bad request | Недопустимый config_type |
| 27 | custom subscription not found | Подписка не найдена |
| 1 | not found | Конфиг не принадлежит пользователю либо для auto_select указан несуществующий ID балансировщика |
| 77 | INVALID_ROUTING_RULES | Некорректные routing_rules, tunnels или quick_toggle_overrides |
| 84 | AUTO_SELECT_NO_TUNNELS | Для config_type: "auto_select" переданы туннели |
| 82 | RESERVED_TAG_NAME | Тег туннеля совпадает с зарезервированным (direct, block, dns-out, fragment, proxy) |
| 81 | DUPLICATE_TUNNEL_TAG | Теги туннелей повторяются |
| 80 | TUNNEL_SELF_REFERENCE | Туннель ссылается на сам редактируемый конфиг |
| 78 | TUNNEL_CONFIG_NOT_FOUND | Конфиг-источник туннеля не найден или не принадлежит пользователю |
| 79 | TUNNEL_INCOMPATIBLE_PROTOCOL | Протокол конфига-источника несовместим с XRay |
| 83 | UNKNOWN_OUTBOUND_TAG | В правиле указан outboundTag, не соответствующий ни одному туннелю |
| 55 | INVALID_DNS_SERVER | В dns_overrides при dns_preset: "custom" не передан custom_dns_url или указан небезопасный хост |
DELETE /profile/custom-subscriptions/:id/routing/configs/:config_type/:config_reference_id
Сбросить настройки маршрутизации для конкретного конфига подписки.
Rate Limit: 3 req / 2 sec
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
config_type | string | Да | Один из: user_config, paid_option_config, paid_option_index, cloud_server_config, auto_select |
config_reference_id | number | Да | ID конфига соответствующего типа (для auto_select — ID балансировщика из custom_auto_selects, 0 для встроенного) |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
config_index | number | Нет | Индекс конфига (по умолчанию: 0) |
Пример запроса
curl -X DELETE "https://api.stealthsurf.net/profile/custom-subscriptions/123/routing/configs/user_config/2?config_index=0" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: true
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 3 | bad request | Недопустимый config_type |
| 27 | custom subscription not found | Подписка не найдена |
GET /profile/custom-subscriptions/:id/routing/available-tunnels
Получить конфиги, доступные для использования в качестве туннелей внутри подписки. Возвращаются только XRay-совместимые конфиги, входящие в состав этой подписки.
Rate Limit: глобальный (60 req/min)
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Да | ID подписки |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
exclude_config_type | string | Нет | Тип конфига для исключения из результата |
exclude_config_id | number | Нет | ID конфига для исключения из результата |
Пример запроса
curl -X GET "https://api.stealthsurf.net/profile/custom-subscriptions/123/routing/available-tunnels" \
-H "Authorization: Bearer stlth_XXXXXXXX_YYYYYYYYYYYYYYYYYYYYYYYY"Ответ
{
status: true,
statusCode: 200,
data: Array<{
config_type: string
config_id: number
config_index?: number // Только для config_type: "paid_option_index"
tag: string // config-N / option-N / cloud-N / ext:N:M
label: string
protocol: string
}>
}Ошибки
| errorCode | message | Когда |
|---|---|---|
| 27 | custom subscription not found | Подписка не найдена |
Помогла ли вам эта статья?