> For the complete documentation index, see [llms.txt](https://docs.tumbler.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tumbler.app/ru/kontrakt-podpiski/response-formats.md).

# Форматы ответа

## Для кого

Разработчики, которые уже сформировали add link и теперь хотят проверить, что именно должен возвращать subscription URL.

## Что можно сделать

* Оставить существующий формат, если он уже поддерживается.
* Понять, какие форматы парсятся строго, а какие best-effort.
* Передать метаданные подписки в теле или HTTP-заголовках.

## См. также

* [getting-started/quickstart.md](/ru/nachat/quickstart.md)
* [getting-started/add-link.md](/ru/nachat/add-link.md)
* [subscription/metadata.md](/ru/kontrakt-podpiski/metadata.md) — список поддерживаемых meta‑полей.
* [operations/caching-and-304.md](/ru/uluchsheniya-posle-pervogo-zapuska/caching-and-304.md)
* [features/basic-limits.md](/ru/funkcii/basic-limits.md)

## Поддерживаемые форматы тела

Tumbler не требует специальный новый формат, если у провайдера уже есть рабочая VLESS/Xray/sing-box подписка. Ниже перечислены допустимые ответы. Первые пять парсятся строго; Xray и sing-box разбираются **best-effort**. Пустое тело или отсутствие валидных VLESS узлов приводят к ошибке.

После парсинга backend приводит provider response к внутреннему normalized snapshot и доставляет мобильному клиенту encrypted runtime payload. Провайдерам нужно опираться на публичный input contract из этой документации: форматы тела ответа, объект `meta` или meta-строки и поддерживаемые HTTP-заголовки.

### 1) Plain text `vless://...` (строго)

Тело — построчный список VLESS ссылок.

Пример:

```
vless://11111111-1111-1111-1111-111111111111@edge.example.com:443?security=reality&pbk=pk1&sid=s1&sni=edge.example.com#Edge-1
vless://22222222-2222-2222-2222-222222222222@ws.example.com:80?type=ws&path=%2Fws#WS
```

* **Источник нод:** каждая непустая строка, начинающаяся с `vless://`.
* **Извлекаемые поля:** сервер, порт, UUID; query `security`, `pbk`, `sid`, `sni`, `fp`, `type/net`; `#fragment`/`remarks/ps` как имя; остальные query складываются в `node.meta`.
* **Типичные ошибки:** отсутствует порт/UUID, неподдерживаемая схема, порт вне диапазона 1–65535, UUID с ошибкой формата.

### 2) Смешанный текст (строго)

VLESS строки вперемешку с meta‑строками `#key: value` или `#key=value`.

Пример:

```
#support-url: https://help.example.com
#hide-settings = true
#mirrors: https://m1.example.com/sub, https://m2.example.com/sub
#subscription-userinfo: upload=123456; download=654321; total=10737418240; expire=1800000000
vless://aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa@node1.example.com:443?security=reality&pbk=pkA&sid=01&sni=node1.example.com#Reality-1
vless://bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb@node2.example.com:2053?type=grpc#GRPC
```

* **Источник нод:** только строки `vless://...`; пустые и иные строки игнорируются.
* **Метаданные:** meta‑строки приводятся к ключам из [metadata.md](/ru/kontrakt-podpiski/metadata.md); правила валидации:
  * `mirrors`: строка через запятую или массив; пробелы вокруг запятых игнорируются; только абсолютные `http/https` URL без userinfo (нельзя `https://user:pass@example.com/sub` — credentials в URL утекают в логи, рефереры и сообщения об ошибках).
  * `installation-limit` / `connection-limit`: неотрицательные целые значения.
* **Типичные ошибки:** после фильтра нет ни одной валидной VLESS ссылки; зеркала с userinfo в URL или без схемы; отрицательные лимиты.

### 3) Base64 подписка (строго)

Если тело похоже на Base64 (std или raw) и после декодирования выглядит как подписка, оно декодируется и разбирается как один из текстовых/JSON форматов.

Пример тела (декодируется в одну VLESS ссылку):

```
dmxlc3M6Ly8xMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTVAZWRnZS5leGFtcGxlLmNvbTo0NDM/c2VjdXJpdHk9cmVhbGl0eSZwYms9QWJDZEVmJnNpZD0xMjM0JnNuaT1lZGdlLmV4YW1wbGUuY29tI0VkZ2UtMQ==
```

* **Источник нод:** из результата декодирования; далее применяется тот же парсер, что и для plain/mixed текстовых списков, JSON массива/объекта, либо JSON‑конфигов (Xray/sing-box).
  * Сначала пробуем распарсить как JSON (`links`/`nodes` или `outbounds` для Xray/sing-box); при ошибке JSON-декодирования переходим на текстовый список.
  * Декодирование Base64 выполняется один раз; вложенные уровни не раскрываются.
* **Типичные ошибки:**
  * Декодируется, но внутри нет ни одной валидной VLESS ссылки или JSON массива/объекта.
  * После декода строка пуста или не выглядит как подписка.

### 4) JSON‑массив элементов подписки

Массив может содержать:

* строки `vless://...`;
* объекты с полями `server/port/uuid`;
* объекты Xray/sing-box конфигов с `outbounds` (из каждого элемента best-effort извлекаются `vless` outbounds).

Пример:

```json
[
  "vless://aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa@a.example.com:443#A",
  { "server": "b.example.com", "port": 8443, "uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "transport": "ws" },
  { "outbounds": [{ "type": "vless", "server": "c.example.com", "server_port": 2053, "uuid": "cccccccc-cccc-cccc-cccc-cccccccccccc" }] }
]
```

* **Источник нод:** каждая строка VLESS, каждый объект с `server`, `port`, `uuid`, а также `vless` outbounds из объектов-конфигов.
* **Типичные ошибки:** пустой массив; в элементах нет ни валидных `vless://`, ни валидных `server/port/uuid`, ни валидных `vless` outbounds.

### 5) JSON‑объект `{ links/meta }` (строго)

Ключ `links` (или `nodes`) содержит массив ссылок или объектов; `meta` — метаданные.

Пример:

```json
{
  "links": [
    "vless://cccccccc-cccc-cccc-cccc-cccccccccccc@c.example.com:443#C"
  ],
  "meta": {
    "support-url": "https://help.example.com",
    "new-url": "https://new.example.com/sub",
    "connection-limit": 2,
    "subscription-userinfo": "upload=123456; download=654321; total=10737418240; expire=1800000000"
  }
}
```

* **Источник нод:** массив `links` (fallback — `nodes`) с теми же правилами, что у JSON‑массива.
* **Метаданные:** берутся из `meta`; порядок перекрытия описан в разделе «Общие правила извлечения VLESS/Reality» ниже.
* **Типичные ошибки:** `links`/`nodes` не массив или не содержат валидных VLESS; mirrors/new-url/new-domain с некорректным URL; отрицательные лимиты.

### 6) Xray JSON (best-effort)

Разбираются outbounds с `type/protocol: "vless"`. Подходит для типичных Xray конфигов.

Поддерживается как одиночный JSON-объект, так и когда такие объекты приходят элементами top-level JSON-массива.

Пример:

```json
{
  "outbounds": [
    {
      "type": "vless",
      "tag": "edge-xray",
      "settings": {
        "vnext": [
          {
            "address": "edge.example.com",
            "port": 443,
            "users": [{ "id": "99999999-9999-9999-9999-999999999999", "flow": "xtls-rprx-vision" }]
          }
        ]
      },
      "streamSettings": {
        "network": "grpc",
        "security": "reality",
        "realitySettings": { "publicKey": "pk-xray", "shortId": "ab12", "serverName": "edge.example.com", "fingerprint": "chrome" }
      },
      "meta": { "group": "xray" }
    }
  ]
}
```

* **Источник нод и поля:**
  * `outbounds[].settings.vnext[].{address/port/users[].id}`; поддерживается и legacy расположение `outbounds[].vnext[]` прямо в outbound без `settings`.
  * Имя: `tag` или `email/remark`.
  * `streamSettings`: `network` → `transport`, `security` → `security`.
  * `realitySettings`: `publicKey/pbk`, `shortId/sid/short_id`, `serverName/sni`, `fingerprint/fp`.
  * `outbound.meta` мержится в `node.meta`.
* **Типичные ошибки:** отсутствуют `users` или `address/port`; `outbounds` не массив; все outbounds имеют другой `type`; параметры Reality вне `streamSettings` игнорируются.

### 7) sing-box JSON (best-effort)

Ищутся `outbounds[].type == "vless"` с обязательными `server/server_port/uuid`.

Поддерживается как одиночный JSON-объект, так и когда такие объекты приходят элементами top-level JSON-массива.

Пример:

```json
{
  "outbounds": [
    {
      "type": "vless",
      "name": "sb-reality",
      "server": "sb.example.com",
      "server_port": 8443,
      "uuid": "88888888-8888-8888-8888-888888888888",
      "transport": { "type": "ws", "path": "/ws" },
      "tls": {
        "server_name": "sb.example.com",
        "utls": { "fingerprint": "chrome" },
        "reality": { "public_key": "pk-sb", "short_id": "cd34" }
      },
      "meta": { "group": "sing-box" }
    }
  ]
}
```

* **Источник нод:** `server/server_port/uuid`; имя из `name/remark/ps` или `tag`; `transport.type` → `network`; `tls.reality` → `security=reality`, `pbk`, `sid`; `tls.server_name` → `sni`; `tls.utls.fingerprint` → `fp`; `meta` копируется в `node.meta`.
* **Типичные ошибки:** отсутствует один из обязательных `server/port/uuid`; неверный тип `server_port`; все outbounds другого типа.

## Общие правила извлечения VLESS/Reality

* Хэшируются `server`, `port`, `uuid`, `security`, `transport`, `pbk`, `sid`, `sni`, `fp`, имя и `meta` — любое изменение меняет `version_id`.
* Дополнительные query‑параметры или неизвестные поля объектов попадают в `node.meta`.
* Метаданные берутся из тела (`meta` объекта или meta‑строк), затем перекрываются HTTP‑заголовками (`X-Subscription-*`, `Support-URL`, `Hide-Settings` и др.); подробнее про ключи и приоритет — в [metadata.md](/ru/kontrakt-podpiski/metadata.md).
* Для заголовка профиля поддерживаются обе формы ключа: `profile-title` и `profile_title` (в заголовках и `meta`).
* Для quota/expiry поддерживается `subscription-userinfo` и прямые ключи `upload`/`download`/`total`/`expire` (`expire-at` alias).
* Контент‑тайп: `application/json; charset=utf-8` по умолчанию; `text/plain; charset=utf-8` для текстовых списков; используйте `Content-Encoding: gzip/zstd` только по договорённости.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tumbler.app/ru/kontrakt-podpiski/response-formats.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
