Prostor user guide
Keys, subscriptions, deep links and subscription server integration
Last updated: August 13, 2026
1. Adding a key or a subscription
Prostor accepts single connection keys and HTTP/HTTPS subscription links. A subscription link must return a list of keys in Base64 or compatible JSON with an outbounds array.
- Copy the single key or the whole subscription URL.
- Open the Prostor home screen.
- Press "From clipboard" or "Add key". The app works out on its own whether it received a key or a subscription.
- On Android and iOS you can press the QR button and scan a QR code with the same value.
- After the import, pick a server and start the connection.
Supported values
http://andhttps://- a subscription link;vless://,ss://,hy2://,hysteria2://- single keys on every platform;vmess://andtrojan://as direct links are additionally supported on Android; these protocols may also arrive inside a compatible JSON subscription.
2. Adding through a deep link
One format for Windows, macOS, iOS and Android:
prostor://add/<URL-encoded key or subscription URL>Example with a subscription link:
prostor://add/https%3A%2F%2Fsub.example.com%2Fs%2FdemoBuilding the link in JavaScript:
const source = 'https://sub.example.com/s/demo'
const deepLink = `prostor://add/${encodeURIComponent(source)}`?, &, # and a nested ://. Opening the deep link takes the app to the home screen and runs the same import as the "From clipboard" button. 3. Removing a key or a subscription
- Open the home screen with the list of configurations.
- For a single key, press the cross to the right of the server row.
- For a subscription, press the bin icon in the subscription block header and confirm.
Removing a subscription deletes the link itself and every server it delivered from the app. It is a local operation: it does not cancel anything or delete your account with the provider.
4. Subscription server integration
When a HTTP/HTTPS subscription is added or refreshed, Prostor sends a GET request. HTTP header names are case-insensitive. Do not cache a personalised response by URL alone: it may depend on X-Hwid and on the platform.
4.1. Headers the app sends
| Header | Platforms | Purpose | Example |
|---|---|---|---|
User-Agent | All platforms | Identifies the client: Prostor/windows, Prostor/macos, Prostor/ios or Prostor/android. | Prostor/ios |
X-Hwid | All platforms | A stable opaque identifier of the device/installation. The server may use it to bind a subscription and limit the number of devices. | A1B2C3D4-… |
X-Device-Model | All platforms | Type or model of the device requesting the subscription. | iPhone |
X-App-Version | All platforms | Application version; on Apple platforms it includes the build number. | 1.0.0.2 |
X-Ver-Os | All platforms | Operating system version of the device. | 18.6 |
Cache-Control / Pragma | All platforms | Forbid serving a cached subscription. The server should build a fresh response for every request. | no-cache, no-store, max-age=0 |
X-Hwid is added by the app automatically. The server should read it from the incoming request - it does not need to be echoed back in the response. Treat the value as a personal technical identifier: do not publish it or write it in full into public logs. Example subscription request
GET /s/demo HTTP/1.1
Host: sub.example.com
User-Agent: Prostor/ios
X-Hwid: A1B2C3D4-…
X-Device-Model: iPhone
X-App-Version: 1.0.0.2
X-Ver-Os: 18.6
Cache-Control: no-cache, no-store, max-age=0
Pragma: no-cache4.2. Response headers Prostor understands
The core parameters set the name, expiry, announcement and links of the subscription. The extended Sub-Info-* and Sub-Expire-* parameters drive the info banner and the renewal warning. Prostor needs no additional Provider ID for these features.
| Header | Platforms | What the app does | Example |
|---|---|---|---|
Subscription-Userinfo | Windows · macOS · iOS · Android | Subscription metadata. expire is a Unix timestamp in seconds and defines the expiry date. The standard upload, download and total fields are accepted but are not shown in the interface right now. | upload=0; download=0; total=107374182400; expire=1798761600 |
Profile-Title | Windows · macOS · iOS · Android | Subscription name in the app. For identical behaviour on every platform, pass UTF-8 text as base64:… | base64:UHJvc3RvciBEZW1v |
Announce | Windows · macOS · iOS · Android | A short plain announcement under the subscription name. The value must use the base64:<UTF-8 in Base64> format. | base64:TmV3IHNlcnZlcnMgYXJlIGF2YWlsYWJsZS4= |
X-Hwid-Limit | Windows · macOS · iOS · Android | If true and the server returns no valid subscription, the app shows a device-limit error instead of a key error. | true |
Profile-Update-Interval | Windows · Android | How often, in hours, the subscription is refreshed automatically when the user has auto-update enabled. | 6 |
Support-Url | Windows · Android* | The provider support link. Windows shows a support action; Android stores the value for compatibility. The value None clears the link. | https://example.com/support |
Profile-Web-Page-Url | Windows · Android* | The subscription web page. Currently stored with the subscription data; a visible button is not present on every platform. The value None clears the link. | https://example.com/account |
Sub-Info-Color | Windows · macOS · iOS · Android | Colour of the info banner: blue, green or red. An unknown value falls back to the brand blue. | blue |
Sub-Info-Text | Windows · macOS · iOS · Android | Text of the coloured banner, 200 characters maximum. Plain UTF-8 text or base64:… is supported. | base64:0JTQvtCx0LDQstC70LXQvdGLINC90L7QstC60LDRhtC40Lg= |
Sub-Info-Button-Text | Windows · macOS · iOS · Android | Text of the info banner button, 25 characters maximum. The button only appears together with a link. | base64:0J/QvtC00YDQvtCx0L3QtdC1 |
Sub-Info-Button-Link | Windows · macOS · iOS · Android | Link of the info banner button. Use HTTPS for compatibility and safety. | https://example.com/news |
Sub-Expire | Windows · macOS · iOS · Android | Enables the subscription expiry warning. The values true and 1 turn the banner on three days before expire; it temporarily replaces Sub-Info-Text. | true |
Sub-Expire-Button-Link | Windows · macOS · iOS · Android | Link of the Renew button in the subscription expiry warning. | https://example.com/renew |
Fallback-Url | Windows · macOS · iOS · Android | A second address serving the same subscription. The app requests it only when the main address does not answer (a network error, or a non-2xx response), and remembers whichever address worked for the next refresh. A refusal from the panel (a device limit, say) counts as an answer, so the fallback is not tried in that case. The value is accepted only when it is an http(s) address - and, in key-only mode, one on a provider domain. The subscription keeps its original address as its identity; it is never swapped. | https://mirror.example.com/s/AbCdEf |
An asterisk next to Android means the value is recognised and stored, but a separate action may be missing from the current interface. For cross-platform integration, rely on the rows that list all four platforms.
4.3. HTTP response format
Prostor reads subscription parameters from real HTTP response headers only. The format is the same for Windows, macOS, iOS and Android.
HTTP response headers - Windows, macOS, iOS and Android
Send the parameters along with a successful subscription response. Header names are case-insensitive.
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Cache-Control: no-store
Profile-Title: base64:UHJvc3RvciBEZW1v
Subscription-Userinfo: upload=0; download=0; total=107374182400; expire=1798761600
dmxlc3M6Ly9leGFtcGxlLWtleS0xX-Hwid-Limit send true. For Sub-Expire the values true and 1 both mean "on". 4.4. Full HTTP response example
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Cache-Control: no-store
Profile-Title: base64:UHJvc3RvciBEZW1v
Subscription-Userinfo: upload=0; download=0; total=107374182400; expire=1798761600
Profile-Update-Interval: 6
Support-Url: https://example.com/support
Sub-Info-Color: blue
Sub-Info-Text: base64:TmV3IHNlcnZlcnMgYXJlIGF2YWlsYWJsZS4=
Sub-Info-Button-Text: base64:0J/QvtC00YDQvtCx0L3QtdC1
Sub-Info-Button-Link: https://example.com/news
Sub-Expire: true
Sub-Expire-Button-Link: https://example.com/renew
dmxlc3M6Ly9leGFtcGxlLWtleS0xCnZsZXNzOi8vZXhhbXBsZS1rZXktMg==4.5. Compatibility rules
- For
Profile-TitleandAnnounceusebase64:followed by Base64 of the UTF-8 string. - For links use an absolute
https://URL. - Send
expireas a Unix timestamp in seconds. - The info banner only appears when
Sub-Info-Textis set. - The info banner button only appears when both its text and its link are set.
- The
Sub-Expirewarning needs a validexpireand shows when three days or fewer remain.
5. If the import did not work
- Check that the key or URL was copied in full, with no quotes or stray spaces.
- Open the subscription URL on its own and make sure the server returns a non-empty body.
- Do not return an HTML login page instead of the list of keys.
- When a device limit is hit, return
X-Hwid-Limit: trueand do not serve a stale cached subscription. - For deep links, check the percent-encoding of the whole nested value.