Bloomдля провайдеров
Документация для VPN-провайдеров

Как оформить подписку в Bloom

Какие заголовки подписки читает приложение Bloom, какими ссылками его открывать, как работает кабинет: подтверждение домена, ответ сервера, логотип и статистика. Всё ниже описывает текущую версию приложения и сервера.

Два способа оформить подписку

Заголовки подписки

бесплатно

Панель отдаёт оформление в заголовках ответа подписки: логотип, цвет, кнопки, объявление, баннеры. Bloom показывает его любому пользователю вашей подписки — без регистрации и без кабинета. Список заголовков — ниже.

Кабинет Bloom

по договорённости

То же оформление, но настраивается на этом сайте, а не в панели: с предпросмотром, историей версий и возвратом к любой из них, статистикой запросов, входом с кодом. Показывается только для доменов, владение которыми вы подтвердили. Условия подключения согласуются с командой Bloom.

Можно и то и другое. Каждое поле, заполненное в кабинете, заменяет такое же из заголовков; пустые поля кабинета берутся из заголовков. Если кабинет перестал отдавать оформление (домен не подтверждён, аккаунт не активен, оплата закончилась), приложение снова показывает оформление из заголовков, а без них — стандартное оформление Bloom.

Заголовки подписки

Bloom читает заголовки ответа на запрос подписки. Имена заголовков — без учёта регистра.

  • Текст не латиницей (русский, эмодзи) передавайте как base64: и текст в UTF-8, закодированный в base64: profile-title: base64:0JzQvtC5IFZQTg== («Мой VPN»). Заголовки HTTP рассчитаны на латиницу, и без base64 iOS покажет вместо букв мусор.
  • Ссылки принимаются только https://, http://, tg:// и mailto:. Ссылку с другой схемой (например, bloom:// или vless://) Bloom молча пропускает.
  • Цвет — шестнадцатеричный: #5B6CF0, 5B6CF0 или #5BF; прозрачность в #RRGGBBAA не учитывается.
  • Bloom представляется заголовком User-Agent: Bloom/<версия> (iOS <версия>; <модель>; compatible; Happ) (без версии iOS и модели, если пользователь выключил «Передавать ID устройства»), поэтому панели, которые отдают заголовок routing только клиентам Happ, отдают его и Bloom. Если в таком ответе нет серверов, Bloom повторяет запрос без «compatible; Happ».

Подписка

ЗаголовокЧто делает в Bloom
subscription-userinfoupload=…; download=…; total=…; expire=… — трафик (байты) и срок (Unix-время). Срок дальше 10 лет Bloom считает бессрочным и дату не показывает.
profile-titleНазвание подписки (до 100 символов), пока пользователь не переименовал её сам. Без него — имя файла из content-disposition, затем домен ссылки.
profile-update-intervalКак часто обновлять подписку, в часах (от 1 до 24; без заголовка — раз в час). Действует, когда в Bloom выбрано автообновление «Авто» — так по умолчанию.
hide-settings: 1Не давать пользователю смотреть и копировать ссылки и конфиги серверов.

Оформление

ЗаголовокЧто делает в Bloom
logo-urlили profile-logo-url, logourl, icon-url, profile-icon-urlЛоготип в карточке сервиса на главном экране, при добавлении подписки и в её подробностях. Требования — в разделе «Логотип».
accent-colorили theme-accent, profile-accent-colorФирменный цвет кнопок, ссылок и цифр главного экрана. Большая кнопка подключения остаётся в цветах Bloom; в светлой и тёмной теме цвет подстраивается, чтобы текст читался.
bot-urlили profile-bot-url, boturlКнопка «Бот» в карточке сервиса.
channel-urlили profile-channel-url, channelurlКнопка «Канал».
support-urlили profile-support-url, supporturlКнопка «Поддержка».
profile-web-page-urlили web-page-url, webpageurl, profile-webpage-urlКнопка «Сайт»; на неё же ведёт «Как продлить», когда подписка закончилась (если нет своей ссылки у блока окончания).
announce-urlили profile-announce-url, announceurlКнопка «Новости».

Кнопок-капсул в карточке сервиса — не больше шести, в порядке: Бот, Канал, Поддержка, Сайт, Новости, затем свои кнопки из bloom-buttons. Одна и та же ссылка дважды не показывается.

Объявление и свои кнопки

ЗаголовокЧто делает в Bloom
announceТекст объявления в карточке сервиса и в сообщении провайдера (до 2000 символов, лучше через base64:).
bloom-buttonsДо трёх своих кнопок: Название|https://…;Название|https://… (название — до 40 символов).

Баннер и окончание подписки

ЗаголовокЧто делает в Bloom
banner-textили bannerЦветной баннер под карточкой сервиса (до 500 символов). Пока подписка закончилась или кончился трафик, баннер не показывается.
banner-button-text, banner-button-urlили banner-urlКнопка баннера (без текста — «Подробнее»). Без ссылки кнопки нет.
banner-bg-colorили banner-colorЦвет баннера. Без него — фирменный цвет (accent-color), а без того — цвет Bloom.
banner-text-color, banner-button-colorЦвет текста и кнопки. Без них цвет выбирается по фону: на светлом фоне (относительная яркость выше 0,30) текст и кнопка тёмные, иначе белые.
expiry-banner-textТекст на главном экране, когда подписка закончилась или кончился трафик — пишите так, чтобы подходило к обоим случаям.
expiry-banner-button-text, expiry-banner-button-urlили expiry-banner-urlКнопка на этом экране (без текста — «Как продлить»). Без ссылки она ведёт на сайт, бота или поддержку — что задано, а без них открывает объявление провайдера.

Маршрутизация и обход блокировок

ЗаголовокЧто делает в Bloom
routingПрофиль маршрутизации в формате Happ: happ://routing/onadd/<base64>, happ://routing/add/<base64> или base64 JSON без ссылки. onadd — профиль может включиться сам, но только если пользователь не выбрал маршрутизацию сам и в профиле нет того, о чём Bloom предупреждает (трафик мимо VPN, сторонний DNS, подмена адресов): иначе он ждёт решения пользователя. add — профиль только появляется в списке. off — не включать профиль провайдера автоматически. Ссылки на гео-файлы в профиле — только https://.
fragmentation-enable: 1fragmentation-packets, fragmentation-length, fragmentation-interval (или -delay)Фрагментация TLS для обхода блокировок, например tlshello, 100-200, 10-20. Действует, пока пользователь не настроил обход блокировок сам.

То же в теле подписки

Если панель не умеет отдавать свои заголовки, часть из них можно положить в тело подписки строками #ключ: значение (тело открытым текстом или в base64). Так читаются profile-title, subscription-userinfo, profile-update-interval, support-url, profile-web-page-url, announce, announce-url, hide-settings и строка happ://routing/…. Заголовок с тем же именем важнее строки в теле. Остальное оформление (логотип, цвет, баннеры, кнопки) — только заголовками или в кабинете.

Пример

profile-title: base64:0JzQvtC5IFZQTg==
subscription-userinfo: upload=0; download=1073741824; total=107374182400; expire=1798675200
profile-update-interval: 6
logo-url: https://example-vpn.com/bloom-logo.png
accent-color: #5B6CF0
bot-url: https://t.me/example_vpn_bot
support-url: https://t.me/example_vpn_support
announce: base64:0KHQutC40LTQutCwIDQwJSDQvdCwINCz0L7QtA==
expiry-banner-text: base64:0JTQvtGB0YLRg9C/INC30LDQutC+0L3Rh9C40LvRgdGPLiDQn9GA0L7QtNC70LjRgtC1INCyINCx0L7RgtC1Lg==
expiry-banner-button-text: base64:0J/RgNC+0LTQu9C40YLRjA==
expiry-banner-button-url: https://t.me/example_vpn_bot?start=renew

Новые заголовки пользователь увидит после следующего обновления подписки в приложении — по расписанию из profile-update-interval или когда обновит её сам.

Страница «Открыть в Bloom»

Ссылку bloom:// не везде можно нажать: Telegram и многие сайты не делают её ссылкой. Для них есть обычная https-страница, которая открывает Bloom:

https://web-bloom.app/add#https://sub.example-vpn.com/api/sub/AbC123
  • Ссылка подписки идёт после # как есть. Эта часть адреса остаётся в браузере пользователя: ни сервер Bloom, ни сеть доставки перед ним, ни бот, который строит превью ссылки, её не получают.
  • Страница сразу пробует открыть Bloom и показывает кнопку «Открыть в Bloom», ссылку для ручного копирования и шаги, если Bloom не установлен. Дальше — как с bloom://add: подписка загрузится только после «Проверить».
  • Если # использовать нельзя, есть https://web-bloom.app/add?url=<ссылка в percent-encoding>. Такая страница работает и без JavaScript, но ссылка подписки тогда приходит на сервер (и в сеть доставки, если она включена). Сервер Bloom её не записывает и не хранит, но лучше вариант с #.

Кабинет: подтверждение домена

Оформление из кабинета показывается только для доменов подписки, владение которыми вы подтвердили. В кабинете можно добавить до 20 доменов (или вставить ссылку подписки целиком — домен возьмётся из неё). Для каждого выдаётся код вида bloom-3f9a…; подтвердить можно любым способом:

  • TXT-запись в DNS: имя _bloom-verify.<домен>, значение — код. Сервер спрашивает 1.1.1.1 и 8.8.8.8, затем свой DNS. Изменения DNS иногда применяются до часа. Для IP-адреса вместо домена этот способ не подходит.
  • HTTP-заголовок в ответе подписки: bloom-verify: <код>. Сервер запрашивает https://<домен>/ или указанную вами ссылку подписки на этом же домене (порт 443, 2053, 2083, 2087, 2096, 8443) с User-Agent: Bloom-Verify/1.0, читает только заголовки, не ходит по перенаправлениям и не подключается к внутренним адресам. Например, nginx: add_header bloom-verify "bloom-3f9a…" always;, Caddy: header bloom-verify "bloom-3f9a…".

Домен может добавить несколько аккаунтов, но подтверждён он только у одного — у того, кто прошёл проверку последним; прежний владелец теряет подтверждение. Так никто не займёт чужой домен, просто добавив его первым.

Не удаляйте запись после подтверждения

Подтверждённые домены сервер проверяет снова раз в сутки — той же проверкой: подходит и TXT-запись, и заголовок. Если подтверждение не находится 3 раза подряд в течение хотя бы 2 дней, домен получает отметку «подтверждение не найдено с <дата>» — её видите вы и администратор Bloom. Брендинг при этом показывается дальше и автоматически не снимается; снять подтверждение может только администратор. Верните запись или заголовок и нажмите в кабинете «Проверить снова» — отметка исчезнет. Домены, подтверждённые администратором вручную, повторно не проверяются.

Как приложение спрашивает кабинет

Bloom берёт домен из ссылки подписки (https://sub.example-vpn.com/api/sub/… → sub.example-vpn.com) и спрашивает:

GET https://web-bloom.app/v1/branding?host=sub.example-vpn.com
  • Когда: при добавлении подписки, при запуске Bloom и возвращении в него, после подключения VPN и после обновления подписок — не чаще раза в 15 минут для каждой подписки. Когда пользователь обновляет подписку сам (кнопка обновления, потянуть экран вниз), Bloom спрашивает сразу. Поэтому изменения из кабинета пользователь видит, когда в следующий раз откроет приложение.
  • Ответ 200 — домен подтверждён, аккаунт активен, оплата действует и оформление сохранено. Поля: name (до 40 символов), logoUrl, accentHex, botUrl, channelUrl, supportUrl, webPageUrl, announceUrl, announce (до 500), banner и expiryBanner (текст до 200, кнопка до 30), routingProfileUrl, updatedAt. Пустые поля не передаются.
  • Ответ 304 — с прошлого раза ничего не изменилось (приложение присылает If-None-Match).
  • Ответ 404 {"error":"not_found"} — оформления из кабинета для этого домена нет. Приложение убирает слой кабинета и показывает оформление из заголовков подписки или стандартное.

Профиль маршрутизации из кабинета (routingProfileUrl) — это ссылка https:// на файл профиля Happ (JSON, base64 или happ://routing/onadd/…). Bloom скачивает его сам и использует, только если в заголовках подписки своего профиля нет; правила включения те же, что у заголовка routing.

Пользователь может выключить запросы к серверу Bloom: «Настройки» → «О приложении» → «Оформление от провайдеров». Тогда он видит только оформление из заголовков.

Статистика в кабинете

  • Запросы — сколько раз приложение спросило оформление для ваших подтверждённых доменов (ответ «не изменилось» тоже считается). Учитываются только пользователи, у которых включено «Оформление от провайдеров», и только дни начиная с подтверждения домена.
  • Устройства — оценка, причём заниженная. За сутки сервер различает запросы по адресу сети и заголовку User-Agent, не сохраняя ни то, ни другое. Bloom присылает одинаковый User-Agent у всех, поэтому все устройства за одним адресом — VPN-сервером, мобильным оператором, домашним роутером — считаются одним. Устройства разных дней не сравниваются, поэтому «за месяц» их не сложить.
  • Цифры за сегодня обновляются раз в минуту, статистика хранится 90 дней. IP-адреса не записываются — подробнее в разделе «Конфиденциальность».

Остались вопросы?

Кабинет: создать аккаунт (бесплатно, редактор с предпросмотром доступен сразу) или войти.