Subscription format
A subscription is an HTTPS URL that returns the server list in the body and the subscription settings in the response headers. This page covers the transport and the body. The headers are in Response headers.
Fetching
Section titled “Fetching”| Aspect | Behavior |
|---|---|
| Method | GET. The request headers are listed in Request headers. |
| Scheme | HTTPS. A plain http:// URL is fetched only after the user confirms the Unencrypted subscription prompt for that subscription; without confirmation the client stops with “HTTPS required; confirm unencrypted HTTP explicitly”. |
| Redirects | 301, 302, 303, 307 and 308 are followed, at most 5 times, and every hop must satisfy the same scheme rule. A redirect without a Location header, or a sixth redirect, is an error. |
| Status | After redirects, any status of 300 or above is an error (“Subscription HTTP 403”). The body of an error response is not parsed. |
| Timeout | 9 seconds by default, applied to connecting, to receiving and to the request as a whole. The provider can set 5 to 15 seconds with subscription-request-timeout. |
| Fallback URL | If the request fails for any reason (timeout, error status, redirect problem), the client retries once with the fallback-url saved from an earlier successful response. The first import has no fallback yet. |
| Size | The response text is limited to 16 MiB. A larger body is rejected as “Import exceeds 16 MiB”. |
| Encoding | UTF-8. A leading byte order mark is ignored. |
| Content-Type | Not checked. |
| Result | On success the server list of the subscription is replaced by the new one. An answer without servers is an error (“Subscription contains no servers; previous servers kept”) and the old list stays. On any error the old servers stay and the message is shown on the subscription card. |
| Schedule | Automatic updates run every profile-update-interval hours (6 hours when the provider sends none), and can be turned off per subscription. |
Body formats
Section titled “Body formats”mins looks at the body in this order and takes the first format that matches. Metadata lines at the top are read first and removed (see Metadata lines).
| # | The body is | Result |
|---|---|---|
| 1 | A single line that is a routing link (mins://routing/..., happ://routing/..., incy://routing/..., incy://autorouting/...) |
A routing profile, no servers |
| 2 | A WireGuard or AmneziaWG INI configuration (first section is [Interface]) |
One server |
| 3 | JSON starting with {, [, // or /* |
Xray configurations, or a routing profile if the object has Name and no outbounds |
| 4 | Text where at least one line contains :// |
A list of links, one per line |
| 5 | Anything else | Treated as base64; the decoded text is parsed again with rules 1 to 4 |
Link list
Section titled “Link list”One link per line. Empty lines are skipped. Supported schemes are vless://, hysteria2:// (and hy2://), wireguard:// and vpn://; the formats are in Links and deep links.
- A link with any other scheme, such as
vmess://ortrojan://, is kept in the list as an unsupported server with the reason “Protocol X is not supported”. The rest of the list imports normally. - A link with a supported scheme that is malformed is not skipped: one invalid link rejects the whole subscription, and the error names the line (
text.lines[N]). Validate your links before serving them. Examples of fatal errors: a transport that was removed (type=h2,http,h3,quic: “Transport removed; use XHTTP”),security=other thannone,tlsorreality, a missingpublickeyin a WireGuard link, an encryptedhapp://crypt...orincy://crypt...link. - A routing link on its own line adds a routing profile to the subscription (see Routing profiles).
Base64
Section titled “Base64”The whole list may be base64-encoded. All four alphabets are accepted: standard and URL-safe, with or without padding. Whitespace and line breaks inside the base64 text are ignored. The decoded text must be UTF-8 and is parsed as any other body; text that decodes to itself is rejected as “Input is not a share link or subscription”. Metadata lines can stay outside the encoded text, above it.
Xray JSON
Section titled “Xray JSON”The body may be one JSON object or an array of objects. Each object is one server. Comments (//, /* */) and trailing commas are allowed.
- An object without a top-level
protocolis a full Xray configuration (withoutbounds, optionallyrouting,dnsand so on). It is used as is; mins changes only its own inbounds, geo references and, when the config has none, DNS. The traffic controlsfragmentation-*,noises-*,mux-*andsniffing-enabledo not apply to it. - An object with a top-level
protocolis a single outbound. mins builds the rest of the configuration around it, so all the traffic controls apply. - The server name is
remarks(orremark), overridden bymins.name; the description ismeta.serverDescription, overridden bymins.description. See The mins block. - Supported outbound protocols are
vless,hysteria(Hysteria2) andwireguard(including AmneziaWG), plusfreedom,blackholeanddnsas helpers. A server using any other protocol is listed as unsupported (“Unsupported protocols: trojan”); the rest imports. - An object with
proxiesorroute(sing-box and Clash shapes) rejects the whole import: “Only Xray configuration imports are supported”.
[ { "remarks": "Finland 1", "meta": { "serverDescription": "Streaming" }, "mins": { "flag": "fi", "icon": "house" }, "outbounds": [ { "tag": "proxy", "protocol": "vless", "settings": { "vnext": [ { "address": "fi.example.com", "port": 443, "users": [ { "id": "11111111-1111-4111-8111-111111111111", "encryption": "none" } ] } ] }, "streamSettings": { "network": "ws", "security": "tls", "tlsSettings": { "serverName": "fi.example.com" }, "wsSettings": { "path": "/ws" } } }, { "tag": "direct", "protocol": "freedom" } ] }]Metadata lines
Section titled “Metadata lines”Subscription settings can travel in the body as #key: value lines instead of, or in addition to, response headers. This is for hosts where you cannot set headers.
#profile-title: Example VPN#profile-update-interval: 12#announce: Planned maintenance on Fridayvless://11111111-1111-4111-8111-111111111111@fi.example.com:443?security=tls#Finland| Rule | Detail |
|---|---|
| Where | Lines at the very top of the body, in any body format (also above base64 text and above JSON). In a link list, # lines between links are read too. |
| Syntax | #key: value. The key is split from the value at the first colon, or at the first whitespace if there is no colon. Spaces around both are trimmed. |
| Keys | Case-insensitive, same names as the response headers. |
| Values | Same rules as headers, including base64: text. An empty value is ignored. |
| Priority | A response header wins over a body line with the same key, including aliases of the same setting. |
| Unknown keys | A comment such as # note: hello is read as key note; it is ignored and listed under Not applied. Harmless, but avoid it. |
Complete example
Section titled “Complete example”HTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8profile-title: base64:RXhhbXBsZSBWUE4=profile-update-interval: 12subscription-userinfo: upload=1073741824; download=5368709120; total=107374182400; expire=1798761600support-url: https://t.me/example_supportprofile-web-page-url: https://example.comannounce: base64:UGxhbm5lZCBtYWludGVuYW5jZSBvbiBGcmlkYXksIDAyOjAwLTAzOjAwIFVUQw==
#profile-description: Three locations, no logsvless://11111111-1111-4111-8111-111111111111@fi.example.com:443?type=ws&security=tls&sni=fi.example.com&path=%2Fws&host=fi.example.com#%F0%9F%87%AB%F0%9F%87%AE%20Finlandhysteria2://s3cret@de.example.com:443/?sni=de.example.com&obfs=salamander&obfs-password=pass#Germanywireguard://AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE%3D@nl.example.com:51820?publickey=AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI%3D&address=10.0.0.2%2F32&dns=1.1.1.1&mtu=1280#NetherlandsThe first server shows a Finland flag: a leading flag emoji in the name sets the country and is removed from the displayed name.
Checklist for panel developers
Section titled “Checklist for panel developers”- Serve over HTTPS. Plain HTTP works only after an explicit confirmation by the user.
- Return
200with the list. Do not answer403or429with a body: the client treats it as an error and keeps the old servers. - Send each header once. Repeated headers with the same name are joined with a comma, which breaks most values.
- Keep
profile-titlewithin 25 characters,announcewithin 200: longer text is cut, not rejected. - Test every link. One malformed link rejects the whole subscription.
- Send
subscription-userinfoon every response: mins draws traffic, expiry and the expiry notification from it.