Управление приложением¶
Параметры для управления поведением приложения через HTTP-заголовки подписки и строки в теле ответа.
Способы передачи¶
Для параметров с поддержкой обоих источников доступны два способа передачи. Исключения, работающие только через HTTP-заголовки (например, перенос URL и баннеры), указаны в соответствующих разделах:
1. HTTP-заголовок:
2. Строка в теле подписки (комментарий с #):
#profile-title: Мой VPN
#support-url: https://t.me/support
#profile-update-interval: 6
#announce: Текст объявления
vless://...
Приоритет: HTTP-заголовки имеют приоритет. Строки в теле подписки используются как fallback, когда соответствующий заголовок отсутствует. Это особенно полезно при раздаче подписок через статические файлы (nginx), где нет возможности задать кастомные HTTP-заголовки.
Стандартные параметры¶
Имя подписки¶
Название профиля подписки. Максимум 25 символов. Можно передавать как текст или base64 (UTF-8).
Заголовок:
В теле подписки:
Base64 с описанием (первая строка — имя, остальные — описание):
Альтернативные заголовки (fallback, если profile-title отсутствует):
- subscription-name — альтернативное имя подписки
- content-disposition — имя файла из заголовка (расширения .txt, .yaml, .yml удаляются автоматически)
Описание подписки¶
Отдельный заголовок для описания, если оно не включено в profile-title:
Поддерживает base64: profile-description: base64:...
Интервал обновления подписки¶
Интервал автоматического обновления подписки в часах. Значение должно быть кратно одному часу.
Заголовок:
В теле подписки:
Интервал обновления геофайлов¶
routing-geo-update-interval — расширение INCY для любого провайдера, передающего профиль маршрутизации с подпиской; Premium не требуется. Оно обновляет geoip.dat и geosite.dat независимо от profile-update-interval и обновления источника Autorouting.
В этом примере подписка обновляется каждый час, геофайлы проверяются раз в 7 дней. Эквивалент в теле — #routing-geo-update-interval: 168, в том числе внутри base64-кодированной текстовой подписки. Принимается целое число часов 0–8760. Некорректные значения игнорируются; корректный заголовок имеет приоритет над телом. Отсутствие или 0 означает отсутствие расписания провайдера. Явно выбранный пользователем интервал или «Не обновлять» имеет приоритет над провайдером.
Интервалы в днях, безопасное скачивание и повторы описаны в разделе автообновления геофайлов.
Статус подписки¶
Информация о балансе, объёме использованного трафика и сроке действия подписки. Поля разделяются точкой с запятой.
| Поле | Описание |
|---|---|
upload |
Исходящий трафик (байт) |
download |
Входящий трафик (байт) |
total |
Лимит трафика (байт) |
expire |
Дата истечения (Unix timestamp, секунды) |
Если
expire> 32 000 000 000 — значение интерпретируется как миллисекунды и конвертируется в секунды.
Ссылка на поддержку¶
Кнопка перехода на страницу поддержки. Если ссылка ведёт в Telegram — отображается иконка Telegram.
Заголовок:
В теле подписки:
Ссылка на сайт¶
Кнопка перехода на сайт подписки.
Заголовок:
В теле подписки:
Альтернативный заголовок: homepage
Объявление¶
Текстовое объявление (до 200 символов). Можно передавать как текст или base64.
Заголовок:
Base64:
URL объявления (ссылка, не текст):
В теле подписки:
#announce: Плановое обслуживание 15 марта
#announce-url: https://example.com/news
vless://uuid@server:443#Server
Сводная таблица параметров¶
| Заголовок | Альтернативы | Формат | Body (#) |
Описание |
|---|---|---|---|---|
new-domain |
— | домен | — | Перенос только этой подписки: заменить хост; только HTTP |
new-url |
— | HTTPS URL | — | Перенос только этой подписки: заменить весь URL; только HTTP |
profile-title |
subscription-name, content-disposition |
текст / base64:... |
✅ | Имя подписки |
profile-description |
— | текст / base64:... |
— | Описание подписки |
profile-update-interval |
— | число (часы) | ✅ | Интервал обновления |
routing-geo-update-interval |
— | целое число часов (0–8760) | ✅ | Автообновление геофайлов профиля; 0 — отключено |
subscription-userinfo |
— | key=value;... |
— | Статистика трафика |
sort-order |
— | none / ping / name |
— | Порядок сортировки серверов (на iOS/Android — для этой подписки; на Desktop — глобально) |
support-url |
— | URL | ✅ | Ссылка на поддержку |
support-email |
— | ✅ | Email поддержки — показывает кнопку «Email» в карточке подписки (запасной контакт). Без заголовка кнопка не показывается | |
profile-web-page-url |
homepage |
URL | ✅ | Ссылка на сайт |
announce |
— | текст / base64:... |
✅ | Текст объявления |
announce-url |
— | URL | ✅ | Ссылка на объявление |
autorouting |
— | URL | ✅ | Автообновляемый профиль маршрутизации |
routing |
— | base64 / ссылка / off |
✅ | Профиль маршрутизации; значение off отключает встроенную маршрутизацию |
premium-url |
— | URL | — | Ссылка «Премиум» (в карточке подписки, см. ниже) |
banner-text |
— | текст / base64:... |
— | Текст баннера (перебивает панель, см. ниже) |
banner-button-text |
— | текст / base64:... |
— | Текст кнопки баннера |
banner-button-url |
banner-url |
URL | — | Ссылка кнопки баннера |
banner-bg-color |
— | hex (#RRGGBB) |
— | Цвет фона баннера |
banner-button-color |
— | hex (#RRGGBB) |
— | Цвет кнопки баннера |
expiry-banner-text |
— | текст / base64:... |
— | Баннер об истечении: текст баннера |
expiry-banner-button-text |
— | текст / base64:... |
— | Баннер об истечении: подпись кнопки |
expiry-banner-button-url |
expiry-banner-url |
URL | — | Баннер об истечении: ссылка кнопки |
expiry-banner-bg-color |
— | hex #RRGGBB |
— | Баннер об истечении: фон баннера |
expiry-banner-button-color |
— | hex #RRGGBB |
— | Баннер об истечении: фон кнопки |
expiry-banner-text-color |
— | hex #RRGGBB |
— | Баннер об истечении: цвет текста баннера |
expiry-banner-button-text-color |
— | hex #RRGGBB |
— | Баннер об истечении: цвет подписи кнопки |
hide-url |
— | 1 / 0 / true / false |
✅ | Скрыть URL подписки от Share/Copy/QR/backup (см. ниже) |
hide-check |
— | 1 / 0 / true / false |
✅¹ | Скрыть кнопку «Проверить» на главном экране (см. ниже) |
per-app-proxy-enable |
— | 1 / 0 |
— | Включить per-app режим (только Android) |
per-app-proxy-mode |
— | bypass / proxy |
— | Режим per-app |
per-app-proxy-list |
— | CSV / URL | — | Список package names |
fragmentation-enable |
— | 1 / 0 |
— | TCP-фрагментация |
fragmentation-length |
— | min-max |
— | Диапазон длины фрагмента |
fragmentation-interval |
— | min-max |
— | Диапазон задержки между фрагментами |
fragmentation-packets |
— | tlshello / 1-3 / all |
— | На какие пакеты применять |
noises-enable |
— | 1 / 0 |
— | Отправка шумовых пакетов до handshake |
noises-type |
— | rand / str / hex |
— | Тип шумового контента |
noises-packet |
— | строка | — | Payload шума (формат зависит от type) |
noises-delay |
— | min-max мс |
— | Диапазон задержки между шумами |
server-address-resolve-enable |
— | 1 / 0 |
— | Предварительный DNS-резолв адреса сервера через DoH |
server-address-resolve-dns-domain |
— | URL | — | URL DoH-сервера |
server-address-resolve-dns-ip |
— | IP | — | IP DoH-сервера (bootstrap) |
no-limit-enabled |
— | 1 / 0 |
— | (iOS) Включить память-экономный режим Network Extension — держит фоновый процесс под лимитом iOS 50 МБ, чтобы xhttp-транспорт не убивался системой (VPN не отваливается). Только включает (не выключает ручной выбор пользователя) |
Все заголовки регистронезависимы (
profile-title=Profile-Title).Параметры из тела подписки (body) используются как fallback — HTTP-заголовки всегда имеют приоритет.
Все заголовки со значениями поддерживают префикс
base64:для передачи UTF-8 данных без проблем с Latin-1 / non-ASCII (применяется кannounce,profile-title,profile-description,subscription-name,per-app-proxy-list,banner-text,banner-button-text).Android и Desktop дополнительно понимают gzip-цепочки в значениях (
base64:gzip:,gzip:base64:,gzip:) — полезно для длинныхper-app-proxy-list. iOS поддерживает толькоbase64:(без gzip).¹
hide-checkкак HTTP-заголовок и через тело подписки (#hide-check:) работает так же, какhide-url, но маркер в теле#hide-check:читают только Android и iOS — Desktop применяетhide-checkтолько через заголовок и Premium-конфиг.⚠️ Кириллица в баннере. HTTP-заголовки не передают non-ASCII напрямую. Чтобы текст баннера или кнопки был на русском, кодируйте его в base64:
banner-text: base64:<base64(UTF-8)>иbanner-button-text: base64:<base64(UTF-8)>.
Маршрутизация¶
Профиль маршрутизации¶
Статический профиль в base64. Подробнее — routing.md.
Значение off (или ссылка ://routing/off) полностью отключает встроенную маршрутизацию:
Автообновляемый профиль маршрутизации¶
URL-источник профиля маршрутизации с периодическим обновлением. Подробнее — autorouting.md.
Приоритет источников маршрутизации¶
Если профиль маршрутизации указан в нескольких местах, используется первый найденный по приоритету:
| Приоритет | Источник |
|---|---|
| 1 (высший) | Заголовок autorouting |
| 2 | Body — строка с URL (://autorouting/onadd/, ://autorouting/add/) |
| 3 | Заголовок routing |
| 4 (низший) | Body — строка с base64 (://routing/onadd/, ://routing/add/, ://routing/) |
Важно: только
://autorouting/устанавливаетsourceURLи включает автообновление. Строки://routing/onadd/{url}в теле подписки импортируют профиль одноразово, без привязки к источнику.
Описание сервера¶
Дополнительная подпись, отображаемая под именем сервера (максимум 30 символов). Добавляется после title через разделитель ?:
Per-app proxy (управление из подписки — только Android)¶
Android VpnService позволяет пропускать через VPN только выбранные приложения либо наоборот — исключать их из туннеля. Провайдер может форсировать этот режим из подписки через три заголовка (только Android). На Desktop сама фича есть, но управляется пользователем — см. подраздел ниже.
per-app-proxy-enable: 1
per-app-proxy-mode: bypass
per-app-proxy-list: com.android.chrome,org.telegram.messenger
Параметры¶
| Заголовок | Значение | Описание |
|---|---|---|
per-app-proxy-enable |
1 / 0 |
Включить режим per-app |
per-app-proxy-mode |
bypass | proxy |
bypass — указанные приложения обходят VPN. proxy — только они идут через VPN |
per-app-proxy-list |
CSV или URL | Список package names через запятую, перенос строки, или URL до текстового файла |
Формат списка¶
Inline (CSV или строчный):
Base64 (для длинных списков):
Удалённый URL:
Файл по URL — обычный plain text с package names по одному на строку или через запятую. Клиент скачивает его при применении подписки и при каждом обновлении.
Поведение¶
- Если ни одно из трёх полей не задано — настройки пользователя в приложении не переопределяются.
- Если
per-app-proxy-enableзадан в0— per-app режим выключается, даже если пользователь его включил локально. - Эти заголовки читает только Android (список — по package names).
Per-app на Desktop (Windows / macOS / Linux)¶
Десктоп-клиент тоже поддерживает per-app split-tunnel, но не через эти заголовки — а как пользовательскую настройку в приложении (экран «Split-tunneling»). Провайдер задать её из подписки не может; список формирует пользователь по именам/путям исполняемых файлов, а не по package names.
Под капотом Desktop не трогает системный firewall — правило пишется прямо в маршрутизацию xray через поле process (сопоставление по PID сокета, sniffing не нужен). Работает и для обычных, и для full-config подписок. Поддержаны Windows, macOS и Linux (движок ядра xray определяет процесс-инициатор: GetExtendedTcpTable на Windows, /proc на Linux, libproc на macOS).
Только в режиме TUN
Per-app на Desktop работает только когда включён режим TUN (xray сам держит TUN-устройство и видит процесс-инициатор). В режимах System Proxy / Proxy Only процесс не определяется, и per-app не применяется.
TCP-фрагментация¶
Перезаписывает глобальные настройки фрагментации пользователя для данной подписки.
fragmentation-enable: 1
fragmentation-packets: tlshello
fragmentation-length: 10-30
fragmentation-interval: 10-30
| Заголовок | Значение | Описание |
|---|---|---|
fragmentation-enable |
1 / 0 |
Включить фрагментацию |
fragmentation-packets |
tlshello | 1-3 | 1 | all |
На какие TCP-пакеты применять фрагментацию |
fragmentation-length |
min-max |
Диапазон длины фрагмента в байтах |
fragmentation-interval |
min-max |
Диапазон задержки между фрагментами в мс |
Те же параметры доступны через Premium API как fragmentEnabled / fragmentPackets / fragmentLength / fragmentInterval — при Premium-подписке HTTP-заголовки игнорируются в пользу API-значений.
Шумовые пакеты (noises)¶
Отправка случайных UDP-пакетов перед VPN-handshake'ом для маскировки. Актуально в первую очередь для WireGuard и Hysteria2 в сетях с глубокой инспекцией трафика.
| Заголовок | Значение | Описание |
|---|---|---|
noises-enable |
1 / 0 |
Включить шумы |
noises-type |
rand | str | hex |
Формат payload'а |
noises-packet |
строка | Содержимое шумового пакета; для rand — диапазон длины min-max |
noises-delay |
min-max мс |
Диапазон задержки между шумовыми пакетами |
Резолв адреса сервера через DoH¶
Bootstrap-резолв домена сервера через DNS-over-HTTPS до установки туннеля. Полезно когда провайдерский DNS подменяет адрес VPN-сервера.
server-address-resolve-enable: 1
server-address-resolve-dns-domain: https://common.dot.dns.yandex.net/dns-query
server-address-resolve-dns-ip: 77.88.8.8
| Заголовок | Значение | Описание |
|---|---|---|
server-address-resolve-enable |
1 / 0 |
Включить DoH-резолв |
server-address-resolve-dns-domain |
URL | DoH endpoint (обычно /dns-query) |
server-address-resolve-dns-ip |
IP | IP DoH-сервера для bootstrap'а — используется до резолва его домена |
Те же поля передаются через Premium API как serverAddressResolveEnable / serverAddressResolveDnsDomain / serverAddressResolveDnsIp.
Ссылка «Премиум»¶
Дополнительная кнопка в карточке подписки — ведёт на страницу покупки или личный кабинет провайдера.
| Заголовок | Значение | Описание |
|---|---|---|
premium-url |
URL | URL кнопки «Премиум» в карточке подписки |
Если не задан — кнопка скрыта.
Баннер провайдера¶
Баннер — заметная плашка в карточке подписки на главном экране (текст + опциональная кнопка). Настраивается в премиум-панели, но текст и кнопку можно переопределить через заголовки подписки — удобно для динамических объявлений без захода в панель.
Условия показа¶
Баннер показывается, когда провайдер — премиум (активная премиум-подписка) и выполнено хотя бы одно из:
- пришёл заголовок
banner-textв ответе подписки (динамический баннер — например, через Remnawave Response Rules, без захода в премиум-панель INCY); или - баннер включён в премиум-панели (
bannerEnabled).
То есть заголовок banner-text сам по себе включает баннер (при условии, что провайдер премиум) — заходить в панель и ставить bannerEnabled не обязательно. Если banner-text не пришёл, баннер показывается по старому пути (панельный bannerEnabled + текст из панели).
Слать баннер через заголовки могут только премиум-провайдеры: для не-премиум подписок
banner-*заголовки игнорируются.
Приоритет: заголовок → панель¶
Каждое поле резолвится как заголовок ?? панель: если соответствующий banner-* заголовок пришёл в ответе подписки — берётся он, иначе — значение из панели.
banner-text: base64:0JDQutGG0LjRjyEg0KHQutC40LTQutCwIDUw0Js=
banner-button-text: Подробнее
banner-button-url: https://example.com/promo
banner-bg-color: #E53E3E
banner-button-color: #38A169
| Заголовок | Формат | Переопределяет (панель) |
|---|---|---|
banner-text |
текст / base64:... |
bannerText |
banner-button-text |
текст / base64:... |
bannerButtonText |
banner-button-url |
URL | bannerButtonUrl |
banner-bg-color |
hex #RRGGBB |
bannerBgColor |
banner-button-color |
hex #RRGGBB |
bannerButtonColor |
Текст (
banner-text) и текст кнопки (banner-button-text) поддерживаютbase64:— для кириллицы/UTF-8 это обязательно (см. предупреждение выше).URL кнопки резолвится как
premium-url→banner-button-url→ панель: заголовокpremium-urlимеет наивысший приоритет (исторически).Если после резолва текст баннера пуст — баннер не показывается.
Поддерживается на iOS, Android и Desktop.
Баннер истекающей и истёкшей подписки¶
Premium-провайдер может переопределить этот баннер HTTP-заголовками ответа подписки. Они независимы от обычного banner-*; premium-url не перебивает ссылку кнопки истечения. Строки # в теле подписки для этих полей не поддерживаются.
| Заголовок | Формат | Поле панели |
|---|---|---|
expiry-banner-text |
текст / base64:... |
expiryBannerText |
expiry-banner-button-text |
текст / base64:... |
expiryBannerButtonText |
expiry-banner-button-url |
URL | expiryBannerButtonUrl |
expiry-banner-bg-color |
hex #RRGGBB |
expiryBannerBgColor |
expiry-banner-button-color |
hex #RRGGBB |
expiryBannerButtonColor |
expiry-banner-text-color |
hex #RRGGBB |
expiryBannerTextColor |
expiry-banner-button-text-color |
hex #RRGGBB |
expiryBannerButtonTextColor |
expiry-banner-text: base64:0J/RgNC+0LTQu9C40YLQtSDQv9C+0LTQv9C40YHQutGD
expiry-banner-button-text: base64:0J/RgNC+0LTQu9C40YLRjA==
expiry-banner-button-url: https://example.com/renew
expiry-banner-bg-color: #082C22
expiry-banner-button-color: #29C896
expiry-banner-text-color: #FFFFFF
expiry-banner-button-text-color: #062018
expiry-banner-url — короткий вариант expiry-banner-button-url. Если переданы оба, приоритет у полного имени. Для обычного баннера также поддерживается banner-url как вариант banner-button-url. Кириллицу и другой не-ASCII текст передавайте через base64:.
Условия показа и приоритет¶
- У провайдера должен быть активен Premium. Для непремиум-подписок эти баннеры не показываются.
- Непустой
expiry-banner-textвключает баннер безexpiryBannerEnabledв панели. Одна ссылка или цвет только переопределяют уже настроенный баннер. - Клиент использует
subscription-userinfo→expire: баннер появляется за 3 дня до истечения или после него. Без известной даты истечения он не включается. Заголовок не меняет срок действия подписки. - Каждое переданное непустое поле имеет приоритет над панелью. Удаление заголовка или пустое значение возвращает значение панели при следующем успешном обновлении подписки. Переопределение сохраняется после перезапуска приложения.
- Обычный баннер объявления/технических работ сохраняет приоритет над обычным баннером истечения. Если в панели настроено отдельное напоминание о продлении после истечения,
expiry-banner-*переопределяет также его текст, кнопку и цвета; расписание его показа не меняется. - Явный текст из заголовка сохраняется после истечения. Без него используется прежний текст из панели или стандартный текст об истечении. Выбирайте формулировку, подходящую до и после срока, либо меняйте ответ динамически.
Поддерживается на iOS, Android и Desktop; на TV ссылка действия отображается QR-кодом. Чтобы клиент получал новые значения и после истечения, провайдер должен продолжать возвращать заголовки и дату истечения в ответе подписки.
Скрытие URL подписки от пользователя¶
Параметр hide-url блокирует «утечку» URL подписки за пределы устройства: при включении приложение не показывает и не разрешает экспортировать URL ни через Share, ни через Copy URL, ни через QR-код, ни в резервные копии. Имя подписки, серверы и весь остальной UX работают как обычно — скрывается только сам URL.
Заголовок:
В теле подписки:
Premium API (JSON):
Принимаемые значения¶
| Что прислано | Поведение |
|---|---|
1, true, yes (без учёта регистра) |
URL скрыт |
0, false, no, пустая строка |
URL открыт (по умолчанию) |
| Любое другое значение в заголовке | Игнорируется, URL открыт |
Приоритет источников¶
- HTTP-заголовок
hide-urlимеет наивысший приоритет - Строка
#hide-url:в теле подписки используется как fallback при отсутствии заголовка - Поле
hide_urlв Premium API JSON — независимый источник, применяется параллельно
Если хотя бы один источник говорит «скрыть» — URL скрывается. Чтобы снять скрытие, отключите его во всех источниках (либо обновите подписку с обновлённым значением).
Что блокируется¶
- Кнопка Share в карточке подписки
- Кнопка Copy URL
- Показ QR-кода подписки
- Включение подписки в резервную копию (даже зашифрованную паролем)
- Кнопка экспорта в редакторе серверов подписки
Что НЕ блокируется¶
- Просмотр и редактирование настроек серверов внутри подписки (на устройствах с admin HWID — см. admin-hwids.md)
- Подключение к серверам, ping, traffic stats, обновление подписки
- Резервные копии отдельных серверов (если они импортированы вручную, вне этой подписки)
Правила для Premium-провайдеров¶
| Premium | Admin HWID | hide-url |
Видит URL | URL в backup |
|---|---|---|---|---|
| нет | — | нет | да | да |
| нет | — | да | нет | нет |
| да | да | нет | да | да |
| да | да | да | да | нет (admin видит, но экспортировать через backup нельзя) |
| да | нет | — | нет | нет |
Без hide-url обычные (не-premium) подписки всегда экспортируются и копируются — hide-url это единственный способ запретить это у не-premium.
Скрытие кнопки «Проверить»¶
Параметр hide-check убирает с главного экрана кнопку «Проверить» (проверка соединения при активном VPN). Работает по той же схеме, что и hide-url: tri-state (задано «скрыть» / задано «показать» / не задано → fallback). По умолчанию кнопка показывается.
Полезно провайдерам, чей сервер отвечает на check-запрос нестандартно (или блокирует его), из-за чего кнопка вводит пользователя в заблуждение.
Заголовок:
В теле подписки (только Android и iOS — Desktop игнорирует маркер в теле):
JSON-тело подписки:
Premium API (JSON):
Принимаемые значения¶
| Что прислано | Поведение |
|---|---|
1, true, yes (без учёта регистра) |
Кнопка «Проверить» скрыта |
0, false, no, пустая строка |
Кнопка показана (по умолчанию) |
| Заголовок отсутствует | Fallback на тело / Premium-конфиг, иначе показана |
Приоритет источников¶
- HTTP-заголовок
hide-check— наивысший приоритет - Маркер
#hide-check:в теле подписки — fallback (Android/iOS) - Поле
settings.hideCheckв Premium API — независимый источник
Платформы¶
Android, iOS и Desktop — все три скрывают кнопку. Отличие только в источнике «тело подписки»: маркер #hide-check: Desktop не читает (используйте заголовок или Premium-конфиг).
Настройки, которые подписка не может задать HTTP-заголовками¶
Эти параметры хранятся в Premium API конфигурации провайдера и применяются клиентом только если домен подписки принадлежит Premium-провайдеру. Включить их «через подписку без аккаунта в панели» нельзя — это by design.
| Группа | Что настраивается | Ссылка |
|---|---|---|
| Lite Mode | Упрощённый интерфейс, ссылки на бот/канал/поддержку + пресет-иконки | premium-api.md § Lite Mode |
| Баннер подписки | Текст + цвета + кнопка в карточке подписки | premium-api.md § Баннер подписки |
| Кастомная тема | Плоские цвета и градиенты для аккаунта / фона | premium-api.md § Кастомная тема |
| Force-настройки | forceConnectionStyle: классическая круглая кнопка vs compact-toggle |
premium-api.md § Принудительные настройки |
| Ping и сортировка | defaultPingProtocol, defaultSortOrder, pingOnUpdate |
premium-api.md § Ping и сортировка |
| Domain fronting | resolveAddress / hostHeader (связка SNI ↔ Host для маскировки) |
premium-api.md § Domain fronting и фрагментация |
| Админ-доступ по HWID | adminHwids + auto-approve пушей |
admin-hwids.md |
| Push-уведомления | Модерация, таргетинг, отмена | provider-notifications.md |
Фрагментация, шумы и DoH-резолв доступны через оба канала: HTTP-заголовками подписки (см. выше) или через Premium API. При Premium-подписке API-значения приоритетнее заголовков.
Перенос конкретной подписки на новый адрес¶
В HTTP-ответе с успешно разобранной подпиской можно передать один из заголовков:
Заменяет только хост: https://old.example.com:8443/sub/token%2F?key=a+b#HWID → https://project-a.example.com:8443/sub/token%2F?key=a+b#HWID. Порт, путь, query-параметры и фрагмент сохраняются без декодирования токена. Значение — только имя домена, без схемы, порта и пути; для международных доменов используйте ASCII/Punycode.
Если меняются также путь или токен, передайте полный адрес:
new-url заменяет весь URL, включая query и фрагмент. Если нужны прежние значения, включите их в новый адрес. При наличии обоих заголовков приоритет у new-url; некорректный new-url не переключает обработку на new-domain. Значения передаются обычным текстом, без base64:; #new-domain: и #new-url: в теле ответа не поддерживаются.
Перенос относится только к подписке, получившей этот ответ. Клиент сохраняет её ID, настройки и привязку маршрутизации; новая карточка не создаётся. Две подписки одного провайдера могут получить разные адреса — ни URL, ни решение о переносе не записываются в общий кэш провайдера. Текущее обновление использует полученный ответ, следующее обращается уже к новому URL.
Проверка перед переносом¶
- Исходный URL, URL фактического ответа после редиректов/fallback и новый URL должны использовать HTTPS без логина/пароля в адресе.
- Все три домена должны быть верифицированы, не удалены и принадлежать одному и тому же провайдеру в панели. Платный статус сам по себе не заменяет проверку домена.
- Панель проверяет актуальные записи по SHA-256 хешам доменов. Путь, токен и полный URL подписки в проверку не передаются; подтверждение не кэшируется.
- Заголовок с тем же доменом, некорректный адрес, конфликт с URL другой сохранённой подписки или изменение исходного URL пользователем во время запроса отменяют перенос. В частности,
new-urlс новым путём, но прежним доменом, игнорируется. - Если панель недоступна, не поддерживает проверку или отказывает в ней, прежний URL сохраняется; обычное обновление успешно полученной подписки продолжается. Пустой/ошибочный ответ подписки не переносит адрес.
Поддержка требует обновлённых клиентов Android/Android TV, iOS/tvOS и Desktop и обновлённой панели с проверкой /api/subscription/resolve?h=…&target=…&origin=…. Это отдельный механизм от общего переноса домена и fallbackHosts. Старый адрес должен ещё отвечать — либо ответ должен приходить через допустимый fallback. Уже полностью недоступный домен не сможет доставить заголовок клиенту.