Link formats¶
Everything the client accepts, in one place. All schemes are case-insensitive.
Server links¶
| Scheme | Payload |
|---|---|
vless:// vmess:// trojan:// ss:// socks:// |
Standard share links, as issued by any panel |
wireguard:// · amneziawg:// · awg:// · wg:// |
base64 of a plain WireGuard .conf — the same text the official client takes — or base64 of xray-style JSON settings |
hysteria2:// · hy2:// |
Accepted and stored, but not yet supported by xray-core — such a server will not connect |
Base64 is read leniently — standard and URL-safe alphabets, with or without padding.
A #fragment sets the display name (percent-encoded). It may also carry a server description — see section 04a.
What “View config” shows¶
The client applies one simple rule: if the link carries base64, it shows the decoded content; otherwise it shows the link as it is. So wireguard://<base64> displays the readable .conf, while vless://uuid@host:443?… stays a link — there is nothing to decode. JSON payloads are pretty-printed.
Subscriptions¶
A subscription URL may return:
-
plain text — one link per line;
-
base64 of that same list;
-
JSON — a full xray config, or a container with several WireGuard/AmneziaWG servers:
type is accepted as amneziawg, awg, wireguard or wg. A broken entry is skipped rather than failing the whole subscription.
Encrypted header values¶
Header values can be sent in a closed form, so links and settings don't travel around in the open. Any subscription header may carry its value encrypted, using the same crypt1/ prefix as the deep links:
routing-update-url: crypt1/<base64>
routing: crypt1/<base64>
autorouting: crypt1/<base64>
s-dns: crypt1/<base64>
s-fragment: crypt1/<base64>
s-resolve: crypt1/<base64>
s-noise: crypt1/<base64>
new-url: crypt1/<base64>
s-siteurl: crypt1/<base64>
The client strips the prefix, decrypts the payload and then treats the result exactly as if it had arrived in the clear. Without the prefix nothing changes — existing subscriptions keep working untouched. Encryption is optional and per-header: a single response can freely mix encrypted and plain values.
The encryption is exactly the one used by smproxy://crypt1/… links — AES-256-GCM, nonce || ciphertext || tag, base64-encoded, under the same shared key. A panel that already issues those links needs no new code: encrypt the value, prefix it with crypt1/, and put it in the header.
To get an encrypted value without writing any code, use the public generator — no authentication needed. The response has two fields: link is the full ready-made link, and cryptedPart is just the encrypted payload, which is what goes into a header after the crypt1/ prefix.
POST https://provider.smproxy.io/public/crypto-link
{ "url": "https://example.com/routing.json" }
→ {
"link": "smproxy://crypt1/AbCd…",
"cryptedPart": "AbCd…"
}
routing-update-url: crypt1/AbCd…
s-dns: crypt1/AbCd…
Encrypted link generator → — public, no sign-in needed. All tools: Link generators.
Both separators are accepted — crypt1/<base64> and crypt1:<base64> — but use the slash: it matches the deep links, so there is one format to remember.
⚠ This is obfuscation, not secrecy. The key ships inside every client, so anyone who takes the app apart can read these values. It keeps the profile URL out of plain sight — away from a casual glance at traffic, or from being pasted into a chat — and nothing more. Do not put anything genuinely sensitive behind it.
Deep links¶
Two schemes are accepted: smproxy:// (current) and smartvpn:// (pre-rename, kept working for links already handed out). That applies to clickable links only — the OS hands a link to the app registered for its scheme. Inside the routing / autorouting headers any scheme word is accepted (section 07a).
| Link | Effect |
|---|---|
smproxy://add?url=<encoded URL> |
Add a subscription |
smproxy://add/<https://…> · add/<base64 URL> |
Same, path form |
smproxy://crypt1/<base64> |
Add from an encrypted payload |
smproxy://routing/add/<base64\|url> |
Import a routing profile, don't switch to it |
smproxy://routing/onadd/<base64\|url> |
Import and activate |
smproxy://autorouting/add\|onadd/<url> |
Same, plus keep it updated from that URL |
smproxy://routing/off |
Turn routing off |
The payload may also be passed as ?data=<base64>. For routing links the target may hold the profile JSON, its base64, or another smproxy:// link — all three resolve.